<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Paul Chen</title>
    <description>The latest articles on DEV Community by Paul Chen (@paul_chen_90371fe7426cb44).</description>
    <link>https://dev.to/paul_chen_90371fe7426cb44</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3898190%2F38f30ba0-280f-4a52-8c7d-c773315b8da8.jpg</url>
      <title>DEV Community: Paul Chen</title>
      <link>https://dev.to/paul_chen_90371fe7426cb44</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/paul_chen_90371fe7426cb44"/>
    <language>en</language>
    <item>
      <title>Synthadoc: From Raw Documents to Domain Intelligence (Youtube)

https://youtu.be/rIGO6zi9XQE?si=nuhdnvdl9pcZ4NV_</title>
      <dc:creator>Paul Chen</dc:creator>
      <pubDate>Sun, 17 May 2026 04:22:14 +0000</pubDate>
      <link>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-from-raw-documents-to-domain-intelligence-youtube-2ha2</link>
      <guid>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-from-raw-documents-to-domain-intelligence-youtube-2ha2</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://youtu.be/rIGO6zi9XQE?si=nuhdnvdl9pcZ4NV_" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;youtu.be&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>productivity</category>
      <category>automation</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Synthadoc: Routing at Scale, Quality Gates, and the Knowledge Backend Pattern</title>
      <dc:creator>Paul Chen</dc:creator>
      <pubDate>Mon, 11 May 2026 14:21:30 +0000</pubDate>
      <link>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-routing-at-scale-quality-gates-and-the-knowledge-backend-pattern-lil</link>
      <guid>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-routing-at-scale-quality-gates-and-the-knowledge-backend-pattern-lil</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwnufzdbrz98r7yj7i6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwnufzdbrz98r7yj7i6c.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;When we shipped v0.1.0, Synthadoc did one thing well: it turned raw sources into a structured wiki that got smarter with every ingest. v0.2.0 made that wiki searchable with hybrid BM25 + vector retrieval. v0.3.0 opened up the source types - YouTube transcripts, web search fan-out, CLI provider integration so your existing Claude Code or Opencode subscription could power the whole thing.&lt;/p&gt;

&lt;p&gt;But a pattern kept surfacing in user feedback. Once a wiki crossed a few hundred pages, three problems appeared in a cluster: queries got slower, low-confidence pages polluted search results, and there was no clean way to pipe the wiki's structured knowledge into an agent prompt without getting back a synthesised answer when you wanted the raw evidence.&lt;/p&gt;

&lt;p&gt;v0.4.0 addresses all three. This post walks through the design decisions behind each feature, the benchmark numbers, and why we think the third one, context packs, points at something larger than a feature.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scale Problem
&lt;/h2&gt;

&lt;p&gt;BM25 is fast. On a 100-page wiki, a query completes in single-digit milliseconds. The problem is that BM25 is also undiscriminating: it scores every page against every query, regardless of how obviously irrelevant most of those pages are.&lt;/p&gt;

&lt;p&gt;That's fine at 100 pages. At 1,000 pages with diverse topics - a personal research wiki covering ML, distributed systems, organisational theory, and management literature - you're running a full-corpus scan for every query. And because query decomposition splits one question into 3–5 sub-questions, you multiply that cost by 3–5 on every call.&lt;/p&gt;

&lt;p&gt;We benchmarked the unrouted baseline across corpus sizes. The numbers aren't alarming until they are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Corpus size&lt;/th&gt;
&lt;th&gt;Full-corpus P95 latency&lt;/th&gt;
&lt;th&gt;Routed P95 latency (2 of 10 branches)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100 pages&lt;/td&gt;
&lt;td&gt;7 ms&lt;/td&gt;
&lt;td&gt;7 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500 pages&lt;/td&gt;
&lt;td&gt;38 ms&lt;/td&gt;
&lt;td&gt;12 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000 pages&lt;/td&gt;
&lt;td&gt;74 ms&lt;/td&gt;
&lt;td&gt;18 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5,000 pages&lt;/td&gt;
&lt;td&gt;112 ms&lt;/td&gt;
&lt;td&gt;21 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10,000 pages&lt;/td&gt;
&lt;td&gt;191 ms&lt;/td&gt;
&lt;td&gt;24 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jprgpopq2w23n2qn97i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jprgpopq2w23n2qn97i.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Routed search stays near-flat as the corpus grows, because the per-branch page count doesn't change even as the total wiki does. Full-corpus search grows with the wiki - not catastrophically, but noticeably, and that growth compounds across decomposed sub-queries.&lt;/p&gt;

&lt;p&gt;The other problem at scale is more subtle: a query about treatment protocols for hypertension shouldn't touch the pages about distributed consensus algorithms. Not just for performance reasons - also because irrelevant pages can drift into synthesis and dilute the answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature 1: Routing Layer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why It Matters for a Self-Growing Wiki
&lt;/h3&gt;

&lt;p&gt;The scale problem above gets worse in a specific way that's easy to underestimate: a well-configured Synthadoc wiki doesn't stay at its initial size. With nightly scheduled ingests pulling from web searches, PDFs, YouTube transcripts, and curated source lists, a wiki can double from 200 to 400 pages within a few weeks, then reach 1,000 within a few months without the user doing anything manually. That's exactly the point.&lt;/p&gt;

&lt;p&gt;But without routing, query quality degrades silently as that growth happens. Every new page increases the BM25 corpus, and the search engine has no way to know that "What are the treatment protocols for hypertension?" should not touch the 300 pages about software architecture. More pages means more irrelevant candidates competing to drift into synthesis, more false positives, and more latency - and none of it is visible until queries start returning noticeably diluted answers.&lt;/p&gt;

&lt;p&gt;Routing is what makes autonomous growth sustainable. It's the mechanism that keeps query scope bounded to what's actually relevant, regardless of how large the total wiki becomes. The branch taxonomy is defined once; IngestAgent maintains it automatically from that point forward - every new page created by ingest is auto-placed into the most relevant branch, so ROUTING.md stays accurate as the wiki grows without manual intervention.&lt;/p&gt;

&lt;p&gt;The routing layer introduces a file called &lt;code&gt;ROUTING.md&lt;/code&gt; at the wiki root. Its format is intentionally simple - the same &lt;code&gt;## H2 → [[slug]]&lt;/code&gt; structure already used in &lt;code&gt;index.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## People&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [[alan-turing]]
&lt;span class="p"&gt;-&lt;/span&gt; [[grace-hopper]]
&lt;span class="p"&gt;-&lt;/span&gt; [[ada-lovelace]]

&lt;span class="gu"&gt;## Hardware&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [[von-neumann-architecture]]
&lt;span class="p"&gt;-&lt;/span&gt; [[eniac-computer]]
&lt;span class="p"&gt;-&lt;/span&gt; [[transistor-and-microchip]]

&lt;span class="gu"&gt;## Networks&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [[internet-origins]]
&lt;span class="p"&gt;-&lt;/span&gt; [[arpanet-history]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User-owned. Scaffold creates it once from the current index structure and never rewrites it. The user defines the branch taxonomy; the system maintains it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Routing Works at Query Time
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3y3wmg9ownompi9nd0se.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3y3wmg9ownompi9nd0se.png" alt=" " width="800" height="1246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At query time, QueryAgent reads &lt;code&gt;ROUTING.md&lt;/code&gt; (cached per session, invalidated on write), passes the branch headings and the user's query to the LLM, and receives back a short JSON array of the 1–2 most relevant branch names. BM25 then runs only over the slugs listed under those branches.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;ROUTING.md&lt;/code&gt; is absent, or if no branch scores above threshold, the system falls back to full-corpus search transparently - no error, no degraded output.&lt;/p&gt;

&lt;p&gt;IngestAgent also uses routing: when a new page is created, it's slotted into the most relevant branch automatically. &lt;code&gt;ROUTING.md&lt;/code&gt; stays consistent without manual maintenance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aliases
&lt;/h3&gt;

&lt;p&gt;The other half of the routing feature is alias resolution. Anyone who maintains a personal knowledge base has personal terminology that diverges from canonical names. You might always call a concept by a shorthand, an acronym, or a translation - and BM25 will miss the connection because the strings don't match.&lt;/p&gt;

&lt;p&gt;Aliases live in each page's YAML frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Alan Turing&lt;/span&gt;
&lt;span class="na"&gt;aliases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;turing&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;the turing paper&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;incomputability guy&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At query time, before BM25 runs, QueryAgent expands any alias matches in the query to their canonical slug. The user's internal vocabulary resolves to the wiki's vocabulary without re-learning what the LLM decided to call things.&lt;/p&gt;

&lt;p&gt;ScaffoldAgent suggests initial aliases when generating a page. Users refine them in Obsidian's Properties panel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protected Scaffold Zone
&lt;/h3&gt;

&lt;p&gt;One problem that appeared as wikis grew: users would hand-edit &lt;code&gt;index.md&lt;/code&gt; to add an introduction, a personal note, a custom link - and the next scaffold run would erase it. Scaffold owned the whole file.&lt;/p&gt;

&lt;p&gt;v0.4.0 introduces a marker line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# My Research Wiki&lt;/span&gt;

My custom introduction and notes here.
Scaffold never touches anything above this line.

&lt;span class="c"&gt;&amp;lt;!-- synthadoc:scaffold --&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## People&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [[alan-turing]] — Theoretical foundations of computation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scaffold only regenerates content below &lt;code&gt;&amp;lt;!-- synthadoc:scaffold --&amp;gt;&lt;/code&gt;. Everything above is preserved verbatim across every scaffold run. The marker is inserted automatically on the first scaffold run if absent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc routing init           &lt;span class="c"&gt;# generate ROUTING.md from current index (one-time)&lt;/span&gt;
synthadoc routing validate       &lt;span class="c"&gt;# report dangling slugs — dry run, no changes&lt;/span&gt;
synthadoc routing clean          &lt;span class="c"&gt;# auto-remove dangling entries&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;routing validate&lt;/code&gt; is worth running after bulk ingests or manual page deletions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dangling slugs in ROUTING.md (3):
  [Hardware]  [[eniac-computer]]
  [People]    [[konrad-zuse]]
  [Networks]  [[arpanet-history]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scheduling for a Self-Growing Wiki
&lt;/h3&gt;

&lt;p&gt;There are two distinct scheduling patterns worth setting up: nightly growth and weekly housekeeping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nightly growth&lt;/strong&gt; — ingest pulls in new sources automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc schedule add &lt;span class="nt"&gt;--op&lt;/span&gt; &lt;span class="s2"&gt;"ingest --batch raw_sources/"&lt;/span&gt; &lt;span class="nt"&gt;--cron&lt;/span&gt; &lt;span class="s2"&gt;"0 2 * * *"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As each ingest job completes, IngestAgent writes the new page to &lt;code&gt;wiki/&lt;/code&gt; and appends its slug to ROUTING.md under the most relevant branch. No manual step needed — the routing index grows alongside the wiki.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weekly housekeeping&lt;/strong&gt; - three operations, run in sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc schedule add &lt;span class="nt"&gt;--op&lt;/span&gt; &lt;span class="s2"&gt;"lint run"&lt;/span&gt;      &lt;span class="nt"&gt;--cron&lt;/span&gt; &lt;span class="s2"&gt;"0 3 * * 0"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki   &lt;span class="c"&gt;# Sunday 3 AM&lt;/span&gt;
synthadoc schedule add &lt;span class="nt"&gt;--op&lt;/span&gt; &lt;span class="s2"&gt;"scaffold"&lt;/span&gt;      &lt;span class="nt"&gt;--cron&lt;/span&gt; &lt;span class="s2"&gt;"0 4 * * 0"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki   &lt;span class="c"&gt;# Sunday 4 AM&lt;/span&gt;
synthadoc schedule add &lt;span class="nt"&gt;--op&lt;/span&gt; &lt;span class="s2"&gt;"routing clean"&lt;/span&gt; &lt;span class="nt"&gt;--cron&lt;/span&gt; &lt;span class="s2"&gt;"0 5 * * 0"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki   &lt;span class="c"&gt;# Sunday 5 AM&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order matters. Lint runs first and removes dead wikilinks left behind by deleted pages. Scaffold runs next and regenerates &lt;code&gt;index.md&lt;/code&gt; to reflect the current page set - new categories get added, empty ones get removed. Routing clean runs last and prunes any dangling slug entries from ROUTING.md that no longer have a corresponding wiki page. After all three, the index and routing table are consistent with the actual state of the wiki.&lt;/p&gt;

&lt;p&gt;One thing to be clear about: &lt;code&gt;routing init&lt;/code&gt; is a one-time setup command, not something to schedule. Running it again would overwrite ROUTING.md and erase any branch customisations you've made since the initial setup. &lt;code&gt;routing clean&lt;/code&gt; is the recurring maintenance command - it only removes entries for missing pages and never touches branch structure.&lt;/p&gt;

&lt;p&gt;If you prefer to declare the schedule in config rather than via the CLI, add a &lt;code&gt;[schedule]&lt;/code&gt; block to &lt;code&gt;.synthadoc/config.toml&lt;/code&gt; and register everything in one step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[schedule]&lt;/span&gt;
&lt;span class="py"&gt;jobs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="py"&gt;op&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ingest --batch raw_sources/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;cron&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0 2 * * *"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="py"&gt;op&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"lint run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="py"&gt;cron&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0 3 * * 0"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="py"&gt;op&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"scaffold"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="py"&gt;cron&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0 4 * * 0"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="py"&gt;op&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"routing clean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;               &lt;span class="py"&gt;cron&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0 5 * * 0"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc schedule apply &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With nightly ingests and a weekly maintenance trio in place, the wiki grows, stays accurate, and self-corrects - without requiring manual intervention.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature 2: Candidates Staging
&lt;/h2&gt;

&lt;p&gt;The second feature addresses a different scale problem: quality at the write path.&lt;/p&gt;

&lt;p&gt;Before v0.4.0, IngestAgent wrote new pages directly to &lt;code&gt;wiki/&lt;/code&gt; with no review step. A high-confidence page about a well-structured source landed right next to a speculative page inferred from a thin web article. Both entered BM25, both appeared in orphan detection and contradiction checks, and both showed up in synthesis - with no signal to distinguish them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Staging Concept
&lt;/h3&gt;

&lt;p&gt;Candidates staging introduces a fork in the write path. Pages go to &lt;code&gt;wiki/candidates/&lt;/code&gt; instead of &lt;code&gt;wiki/&lt;/code&gt; when they don't meet a configurable confidence threshold. They're excluded from BM25, orphan detection, and contradiction checks until explicitly promoted.&lt;/p&gt;

&lt;p&gt;The policy is configured in &lt;code&gt;.synthadoc/config.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[ingest]&lt;/span&gt;
&lt;span class="py"&gt;staging_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"threshold"&lt;/span&gt;      &lt;span class="c"&gt;# "off" | "all" | "threshold"&lt;/span&gt;
&lt;span class="py"&gt;staging_confidence_min&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"high"&lt;/span&gt;   &lt;span class="c"&gt;# "high" | "medium" | "low"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three policies:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"off"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All new pages go directly to&lt;code&gt;wiki/&lt;/code&gt; - current behaviour, default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"threshold"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pages meeting&lt;code&gt;staging_confidence_min&lt;/code&gt; auto-promote; lower confidence → &lt;code&gt;wiki/candidates/&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"all"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every new page requires explicit promotion, regardless of confidence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The config is hot-reloaded - a policy change takes effect on the next ingest job with no server restart.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Staging Workflow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5z61xmxn00k3lfhu3si.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5z61xmxn00k3lfhu3si.png" alt=" " width="800" height="1477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing Candidates
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc candidates list

Candidates &lt;span class="o"&gt;(&lt;/span&gt;3&lt;span class="o"&gt;)&lt;/span&gt;:
  eniac-computer    confidence: low     ingested: 2026-05-05
  konrad-zuse       confidence: medium  ingested: 2026-05-05
  arpanet-history   confidence: high    ingested: 2026-05-04

synthadoc candidates promote arpanet-history
synthadoc candidates discard eniac-computer
synthadoc candidates promote &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Promotion does four things atomically: moves the file from &lt;code&gt;wiki/candidates/&lt;/code&gt; to &lt;code&gt;wiki/&lt;/code&gt;, appends the slug to &lt;code&gt;index.md&lt;/code&gt; under the best-matching category, appends it to &lt;code&gt;ROUTING.md&lt;/code&gt; under the best-matching branch, and records the promotion in the audit trail. Discard deletes the file and records the reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduling and Staging
&lt;/h3&gt;

&lt;p&gt;Unlike routing and lint, candidates staging doesn't have a useful scheduled action. The two available commands — &lt;code&gt;candidates promote --all&lt;/code&gt; and &lt;code&gt;candidates discard --all&lt;/code&gt; - are too blunt to schedule safely. Scheduling &lt;code&gt;promote --all&lt;/code&gt; on a timer would auto-approve exactly the pages the quality gate held back. Scheduling &lt;code&gt;discard --all&lt;/code&gt; would silently delete pages you haven't reviewed yet. Neither command has a &lt;code&gt;--older-than&lt;/code&gt; or &lt;code&gt;--confidence&lt;/code&gt; filter that would make scheduled execution sensible.&lt;/p&gt;

&lt;p&gt;The right integration is manual: run &lt;code&gt;candidates list&lt;/code&gt; after a large batch ingest, or once a week if the wiki is growing quickly. It takes seconds. The review step is the intentional human checkpoint in an otherwise automated pipeline, it's where you decide what enters the wiki's searchable knowledge base.&lt;/p&gt;

&lt;p&gt;If candidates are accumulating faster than you can review them, the right response is to adjust the policy rather than schedule a cleanup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Widen the auto-promote threshold - fewer pages need review&lt;/span&gt;
synthadoc staging policy threshold &lt;span class="nt"&gt;--min-confidence&lt;/span&gt; medium

&lt;span class="c"&gt;# Or turn staging off entirely - if you trust all your sources&lt;/span&gt;
synthadoc staging policy off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The staging policy is the dial; the CLI review commands are for the remainder that needs a human decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Matters
&lt;/h3&gt;

&lt;p&gt;The practical effect of &lt;code&gt;staging_policy = "threshold"&lt;/code&gt; on a high-volume wiki is significant. After ingesting 30 web articles from varied sources, typical results look like: 22 high-confidence pages auto-promote and enter the main wiki immediately; 8 lower-confidence pages wait in candidates. Those 8 include speculative pages, ambiguous slug assignments, and pages where the source was thin enough that the LLM wasn't confident what it was describing.&lt;/p&gt;

&lt;p&gt;In the full-corpus approach, those 8 pages would be silently diluting every query that touched their topic. In the staged approach, they're visible and actionable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature 3: Context Packs
&lt;/h2&gt;

&lt;p&gt;The third feature came from a different direction. Users weren't asking "how do I get a better answer?" They were asking "how do I get the raw evidence so I can do something with it myself?"&lt;/p&gt;

&lt;p&gt;QueryAgent synthesises. That's its job. But synthesis isn't always what you want. Sometimes you want the actual page excerpts - cited, bounded, ranked by relevance - to paste into an agent prompt, to attach to a report, to review before a meeting, or to feed into an automated pipeline.&lt;/p&gt;

&lt;p&gt;Context packs are the answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Context Packs Work
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm6nku6q0jxx8nxg02zk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm6nku6q0jxx8nxg02zk.png" alt=" " width="800" height="1268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ContextAgent&lt;/code&gt; reuses &lt;code&gt;QueryAgent.decompose()&lt;/code&gt; and &lt;code&gt;HybridSearch&lt;/code&gt;. It doesn't synthesise - it packs. Each page excerpt is included verbatim (up to its per-page limit), with attribution: slug, relevance score, confidence level, tags, source path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Output Format
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Context Pack: history of early computing pioneers&lt;/span&gt;
Generated: 2026-05-09T14:22:01
Token budget: 4000 | Used: 3847 | Omitted: 2 pages (budget exceeded)
&lt;span class="p"&gt;
---
&lt;/span&gt;
&lt;span class="gu"&gt;## [[alan-turing]] - relevance: 0.92&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Alan Turing developed the theoretical foundations of computation with his 1936&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; paper "On Computable Numbers." The paper introduced the abstract Turing machine&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; and proved the existence of undecidable problems...&lt;/span&gt;
Source: &lt;span class="sb"&gt;`wiki/alan-turing.md`&lt;/span&gt; | Confidence: high | Tags: people, mathematics

&lt;span class="gu"&gt;## [[grace-hopper]] - relevance: 0.87&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Grace Hopper pioneered compiler development and made programming accessible to&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; humans. She developed the first compiler (A-0) in 1952 and later led the team&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; that created COBOL...&lt;/span&gt;
Source: &lt;span class="sb"&gt;`wiki/grace-hopper.md`&lt;/span&gt; | Confidence: high | Tags: people, software
&lt;span class="p"&gt;
---
&lt;/span&gt;
&lt;span class="gu"&gt;## Omitted — token budget exceeded&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [[von-neumann-architecture]] — ~820 tokens
&lt;span class="p"&gt;-&lt;/span&gt; [[eniac-computer]] — ~650 tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CLI Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc context build &lt;span class="s2"&gt;"microservices patterns"&lt;/span&gt;
synthadoc context build &lt;span class="s2"&gt;"microservices patterns"&lt;/span&gt; &lt;span class="nt"&gt;--tokens&lt;/span&gt; 8000
synthadoc context build &lt;span class="s2"&gt;"microservices patterns"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; context.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Token Budget Control
&lt;/h3&gt;

&lt;p&gt;This is where context packs differ from simply querying the wiki. An external agent doesn't want an unbounded blob of text - it has its own context window to manage, its own prompt already taking up tokens, and its own cost constraints. The &lt;code&gt;token_budget&lt;/code&gt; parameter gives the caller precise control over how much of the wiki's knowledge gets included.&lt;/p&gt;

&lt;p&gt;Synthadoc packs pages greedily by relevance score until the budget is exhausted, then lists everything that didn't fit with estimated token counts. The calling agent knows exactly what it got and what it didn't - and can decide whether to request a larger budget, run a second more focused query, or proceed with what's there. There are no surprises about how much context the call will consume.&lt;/p&gt;

&lt;p&gt;This predictability is what makes context packs suitable for production agentic pipelines. An agent orchestrator can reserve a fixed token slice for domain knowledge, call &lt;code&gt;context/build&lt;/code&gt; with that exact budget, and get back a response that fits - every time, regardless of how large the underlying wiki has grown.&lt;/p&gt;

&lt;h3&gt;
  
  
  The REST API - Synthadoc as a Knowledge Backend
&lt;/h3&gt;

&lt;p&gt;Context packs expose a &lt;code&gt;POST /context/build&lt;/code&gt; endpoint that returns the same data as structured JSON. This is where the pattern becomes interesting.&lt;/p&gt;

&lt;p&gt;An agent that needs grounding context before reasoning can call Synthadoc's REST API directly, get back a bounded, cited, ranked set of page excerpts, and inject them into its own prompt - without going through a synthesis step. Synthadoc becomes the knowledge layer, the agent provides the reasoning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/context/build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"goal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"microservices patterns for high-throughput event processing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"token_budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"goal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"token_budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tokens_used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3847&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"slug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"event-driven-architecture"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"relevance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"excerpt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Event-driven architecture decouples producers from consumers..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiki/event-driven-architecture.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"architecture"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"distributed-systems"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"omitted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"slug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kafka-internals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"estimated_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;980&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The existing MCP server exposes this as a native tool call. An agent running in any MCP-compatible host can call &lt;code&gt;context/build&lt;/code&gt; before it reasons, get structured evidence back, and proceed with grounding it wouldn't otherwise have.&lt;/p&gt;

&lt;p&gt;This is what we mean by the "knowledge backend pattern": Synthadoc manages accumulation, deduplication, contradiction detection, and retrieval. The calling agent manages reasoning and action. The division of labour is clean, the token envelope is caller-controlled, and the knowledge layer is persistent across agent sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Other v0.4.0 Changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Plugin Install CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc plugin &lt;span class="nb"&gt;install &lt;/span&gt;history-of-computing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In earlier versions, installing the Obsidian plugin required locating the plugins directory manually, copying files, and restarting Obsidian. v0.4.0 adds a single CLI command that installs the plugin directly into the active Obsidian vault. That's the entire CLI step - the rest is done in Obsidian.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Research Demo: Contradiction Detection End-to-End
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;demos/ai-research/&lt;/code&gt; demo now includes a PDF source (&lt;code&gt;llm-benchmarks-q1-2026.pdf&lt;/code&gt;) that explicitly disputes a claim in the existing wiki. Running the demo shows the full contradiction detection and flagging lifecycle: source ingested, existing page status updated to &lt;code&gt;contradicted&lt;/code&gt;, audit event recorded. The demo now covers all five IngestAgent decision paths - create, update, skip, flag, and contradiction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decision Cache Prompt-Awareness
&lt;/h3&gt;

&lt;p&gt;A quiet but consequential fix: the LLM decision cache key previously included only the content hash and existing slugs. This meant that changes to &lt;code&gt;purpose.md&lt;/code&gt; - the file that scopes what belongs in the wiki - were invisible to the cache. An ingest run after a purpose change would serve stale decisions for any source whose content hadn't changed. v0.4.0 includes the decision prompt itself in the cache key, so any change to &lt;code&gt;purpose.md&lt;/code&gt; automatically busts the cache for all affected sources.&lt;/p&gt;




&lt;h2&gt;
  
  
  v0.1 to v0.4: What Changed
&lt;/h2&gt;

&lt;p&gt;It's worth stepping back to see what the four versions have built:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Core addition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;td&gt;Ingest-time synthesis: sources become a structured wiki, not raw chunks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v0.2.0&lt;/td&gt;
&lt;td&gt;Hybrid BM25 + vector search; query decomposition; knowledge gap detection; full audit trail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v0.3.0&lt;/td&gt;
&lt;td&gt;YouTube and web search ingestion; CLI provider integration (Claude Code &amp;amp; Opencode support); CJK support; contradiction detection improvements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v0.4.0&lt;/td&gt;
&lt;td&gt;Routing at scale; candidates staging for quality control; context packs as a knowledge backend API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first two versions established the ingest-then-query model and made it trustworthy - every action audited, every contradiction surfaced. The third version expanded what you could ingest and who could afford to run it. The fourth version addresses what happens when the wiki grows to a size where the original flat model starts to show cracks.&lt;/p&gt;

&lt;p&gt;The routing benchmarks are honest about where we are: 191ms for a full-corpus query across 10,000 pages is fine for interactive use, but it compounds across sub-questions and becomes a real cost in high-throughput agentic pipelines. The routed 24ms figure at the same corpus size is where we want the system to be. The benchmark-gated release process we introduced in v0.4.0 is the mechanism that ensures it stays there as the codebase evolves.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try Synthadoc v0.4.0
&lt;/h2&gt;

&lt;p&gt;Synthadoc v0.4.0 is available now on GitHub under the AGPL-3.0 licence. The quickest path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/axoviq-ai/synthadoc.git
&lt;span class="nb"&gt;cd &lt;/span&gt;synthadoc
pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
synthadoc &lt;span class="nb"&gt;install &lt;/span&gt;history-of-computing &lt;span class="nt"&gt;--target&lt;/span&gt; ~/wikis &lt;span class="nt"&gt;--demo&lt;/span&gt;
synthadoc plugin &lt;span class="nb"&gt;install &lt;/span&gt;history-of-computing
synthadoc use history-of-computing
synthadoc serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open Obsidian, open &lt;code&gt;~/wikis/history-of-computing&lt;/code&gt; as a vault, install the Dataview community plugin, and enable the Synthadoc plugin. The demo wiki runs against Gemini Flash 2.0, which is free-tier eligible — no cost to run a full ingest-query-lint cycle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/axoviq-ai/synthadoc" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quick-start guide:&lt;/strong&gt; &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/user-quick-start-guide.md" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc/blob/main/docs/user-quick-start-guide.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design document:&lt;/strong&gt; &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/design.md" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc/blob/main/docs/design.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release notes:&lt;/strong&gt; &lt;a href="https://github.com/axoviq-ai/synthadoc/releases/tag/v0.4.0" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc/releases/tag/v0.4.0&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedbacks are welcome. The routing taxonomy and context pack output format are both early - if your use case pushes against their current shape, we want to know.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>rag</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Synthadoc: Your Coding Tool Is Now Your Wiki Brain</title>
      <dc:creator>Paul Chen</dc:creator>
      <pubDate>Tue, 05 May 2026 16:02:35 +0000</pubDate>
      <link>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-your-coding-tool-is-now-your-wiki-brain-41ib</link>
      <guid>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-your-coding-tool-is-now-your-wiki-brain-41ib</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk58cng7aldg2hl5s9c8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk58cng7aldg2hl5s9c8p.png" alt=" " width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you use Claude Code or Opencode, you are already paying for an LLM subscription.&lt;/p&gt;

&lt;p&gt;Before v0.3.0, running Synthadoc also required a separate API key - Anthropic, OpenAI, Gemini, or one of the others.&lt;/p&gt;

&lt;p&gt;v0.3.0 removes that requirement. Set &lt;code&gt;provider = "claude-code"&lt;/code&gt; in one config file and your coding tool subscription becomes the brain of your personal wiki. No additional API key. No additional cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters Beyond Convenience
&lt;/h2&gt;

&lt;p&gt;The obvious win is billing consolidation. But there is a more interesting point underneath it.&lt;/p&gt;

&lt;p&gt;Coding tools like Claude Code and Opencode started as pair programmers. They answer questions about your codebase. They write functions, fix bugs, explain unfamiliar code. That is what the marketing says.&lt;/p&gt;

&lt;p&gt;What they actually are is a general-purpose LLM with a subscription model - capable of anything the underlying model can do, not just code. The coding framing is a UI convention, not a capability limit.&lt;/p&gt;

&lt;p&gt;Synthadoc v0.3.0 makes that explicit. The same Claude subscription you use to navigate a TypeScript monorepo can now synthesize your research documents, detect contradictions in your notes, and answer structured questions about your domain knowledge. The subscription becomes infrastructure, not a point tool.&lt;/p&gt;

&lt;p&gt;This is the same pattern that made cloud storage interesting once it stopped being "backup for photos" and became "filesystem for any application." The value is in the generality.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;Synthadoc's LLM providers are abstracted behind a single &lt;code&gt;LLMProvider&lt;/code&gt; interface. Every agent - IngestAgent, QueryAgent, LintAgent - calls &lt;code&gt;provider.complete()&lt;/code&gt; and receives a structured response. The provider implementation handles everything underneath: API calls, authentication, response parsing, error handling, quota detection.&lt;/p&gt;

&lt;p&gt;For cloud APIs (Anthropic, OpenAI, Gemini), the provider sends an HTTP request. For Claude Code and Opencode, a new &lt;code&gt;CodingToolCLIProvider&lt;/code&gt; class takes a different route: it launches the CLI tool as a subprocess, passes the prompt via stdin, reads the response from stdout, and parses the output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# .synthadoc/config.toml&lt;/span&gt;
&lt;span class="nn"&gt;[agents]&lt;/span&gt;
&lt;span class="py"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"claude-code"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;lint&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"claude-code"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the entire configuration change. No API keys to set. No environment variables.&lt;/p&gt;

&lt;p&gt;The server also accepts a runtime override:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc serve &lt;span class="nt"&gt;-w&lt;/span&gt; my-wiki &lt;span class="nt"&gt;--provider&lt;/span&gt; claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This overrides &lt;code&gt;config.toml&lt;/code&gt; for the lifetime of the server process - useful for quickly switching providers without editing files.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrow6l186yn4q604v2r1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrow6l186yn4q604v2r1.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1 - All agents share one provider interface. CLI providers slot in without changing anything else in the stack.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Works, What Does Not
&lt;/h2&gt;

&lt;p&gt;The CLI provider route is not a perfect substitute for a direct API connection. Two limitations matter:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No vector embeddings.&lt;/strong&gt; Synthadoc's optional semantic re-ranking (hybrid BM25 + vector search) requires an &lt;code&gt;embed()&lt;/code&gt; call, which the CLI tools do not expose. When using a CLI provider, search falls back to BM25-only. For most wikis up to a few hundred pages, BM25 is fast and accurate - this only matters if you have enabled vector search and are running a large corpus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quota is shared.&lt;/strong&gt; Your CLI provider subscription has a daily or session quota. Heavy ingest operations - batch-ingesting 50 documents, for example - consume from the same budget as your coding work. The engine detects quota exhaustion, permanently fails the job with a clear message, and does not retry. You resume after the quota resets.&lt;/p&gt;

&lt;p&gt;Both are manageable trade-offs for a personal wiki. If you need vector search or are running a high-volume ingest, a direct API key is the better choice — pick from any of the eight providers based on your quality, vision, and budget requirements. If you want zero additional configuration and are comfortable with BM25 search, the CLI provider path is clean.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Provider Landscape in v0.3.0
&lt;/h2&gt;

&lt;p&gt;One of the quieter design decisions in Synthadoc is that the LLM provider is not baked into the product. You pick the one that fits your constraints:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;API Key Required&lt;/th&gt;
&lt;th&gt;Free Tier&lt;/th&gt;
&lt;th&gt;Vision&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini Flash&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;1M tokens/day, no credit card&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Default; best free option&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Groq&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Rate-limited&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Fast, good for text-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ollama&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Fully local&lt;/td&gt;
&lt;td&gt;Model-dependent&lt;/td&gt;
&lt;td&gt;Runs on your machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (cheap)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Very low cost per token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MiniMax&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Included with subscription&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;New in v0.3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Opencode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Included with subscription&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;New in v0.3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0db5vay76t97p8x28mpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0db5vay76t97p8x28mpf.png" alt=" " width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2 — Per-agent model routing from a single subscription. Ingest and query use Opus for synthesis quality; lint uses Haiku for speed and lower quota consumption. Two config lines; one bill.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;DeepSeek is also new in v0.3.0 - routes through the OpenAI-compatible endpoint, very low cost per token for text-heavy ingest workloads, and the R1 reasoning model &lt;code&gt;&amp;lt;think&amp;gt;&lt;/code&gt; tags are stripped automatically before the response reaches Synthadoc.&lt;/p&gt;

&lt;p&gt;The point of this table is not that any one provider is the best. It is that you should not need to change your workflow to use the tool. If you are already set up with Anthropic for Claude Code, switching your wiki to the same provider takes one config line.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quota Exhaustion and Reliability
&lt;/h2&gt;

&lt;p&gt;One detail the implementation gets right: quota exhaustion is a permanent failure, not a retryable one.&lt;/p&gt;

&lt;p&gt;Most LLM API errors are transient - a timeout, a 5xx from an overloaded endpoint. Synthadoc retries those with exponential backoff. Quota exhaustion is different. Retrying a quota-exhausted call wastes the next request, then the one after that, burning whatever small remaining budget exists.&lt;/p&gt;

&lt;p&gt;When a &lt;code&gt;CodingToolCLIProvider&lt;/code&gt; detects that the subprocess output indicates quota exhaustion, it raises &lt;code&gt;CodingToolQuotaExhaustedException&lt;/code&gt;. The orchestrator catches this and calls &lt;code&gt;fail_permanent()&lt;/code&gt; on the job - no retries, no backoff. The job sits in &lt;code&gt;failed&lt;/code&gt; state with a clear message: "Claude Code quota exhausted. Resume after quota resets." You do not return to find a queue of 50 failed retries.&lt;/p&gt;

&lt;p&gt;Small detail. Meaningful when it happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started with Claude Code or Opencode Provider
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite:&lt;/strong&gt; Claude Code or Opencode must already be installed and logged in on your machine. If not, follow the &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code setup guide&lt;/a&gt; or the &lt;a href="https://opencode.ai/docs" rel="noopener noreferrer"&gt;Opencode setup guide&lt;/a&gt; first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Clone and install&lt;/span&gt;
git clone https://github.com/axoviq-ai/synthadoc.git
&lt;span class="nb"&gt;cd &lt;/span&gt;synthadoc
pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 2. Install the demo wiki&lt;/span&gt;
&lt;span class="c"&gt;# Linux / macOS&lt;/span&gt;
synthadoc &lt;span class="nb"&gt;install &lt;/span&gt;history-of-computing &lt;span class="nt"&gt;--target&lt;/span&gt; ~/wikis &lt;span class="nt"&gt;--demo&lt;/span&gt;

&lt;span class="c"&gt;# Windows&lt;/span&gt;
synthadoc &lt;span class="nb"&gt;install &lt;/span&gt;history-of-computing &lt;span class="nt"&gt;--target&lt;/span&gt; %USERPROFILE%&lt;span class="se"&gt;\w&lt;/span&gt;ikis &lt;span class="nt"&gt;--demo&lt;/span&gt;

&lt;span class="c"&gt;# 3. Set as the active wiki (no -w needed from here on)&lt;/span&gt;
synthadoc use history-of-computing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Configure the CLI provider&lt;/strong&gt; - edit &lt;code&gt;~/wikis/history-of-computing/.synthadoc/config.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[agents]&lt;/span&gt;
&lt;span class="py"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"claude-code"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or skip editing config.toml entirely and pass &lt;code&gt;--provider&lt;/code&gt; at startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 5. Start the engine - no API key needed&lt;/span&gt;
synthadoc serve &lt;span class="nt"&gt;--provider&lt;/span&gt; claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Install the Obsidian plugin&lt;/strong&gt; - from the cloned &lt;code&gt;synthadoc/&lt;/code&gt; repo directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux / macOS&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/synthadoc   &lt;span class="c"&gt;# or wherever you cloned it&lt;/span&gt;
&lt;span class="nv"&gt;vault&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/wikis/history-of-computing
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$vault&lt;/span&gt;&lt;span class="s2"&gt;/.obsidian/plugins/synthadoc"&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;obsidian-plugin/main.js obsidian-plugin/manifest.json &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$vault&lt;/span&gt;&lt;span class="s2"&gt;/.obsidian/plugins/synthadoc/"&lt;/span&gt;

&lt;span class="c"&gt;# Windows (cmd.exe)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; %USERPROFILE%&lt;span class="se"&gt;\s&lt;/span&gt;ynthadoc
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="s2"&gt;"%USERPROFILE%&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="s2"&gt;ikis&lt;/span&gt;&lt;span class="se"&gt;\h&lt;/span&gt;&lt;span class="s2"&gt;istory-of-computing&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;obsidian&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;lugins&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;ynthadoc"&lt;/span&gt;
copy obsidian-plugin&lt;span class="se"&gt;\m&lt;/span&gt;ain.js &lt;span class="s2"&gt;"%USERPROFILE%&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="s2"&gt;ikis&lt;/span&gt;&lt;span class="se"&gt;\h&lt;/span&gt;&lt;span class="s2"&gt;istory-of-computing&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;obsidian&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;lugins&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;ynthadoc&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
copy obsidian-plugin&lt;/span&gt;&lt;span class="se"&gt;\m&lt;/span&gt;&lt;span class="s2"&gt;anifest.json "&lt;/span&gt;%USERPROFILE%&lt;span class="se"&gt;\w&lt;/span&gt;ikis&lt;span class="se"&gt;\h&lt;/span&gt;istory-of-computing&lt;span class="se"&gt;\.&lt;/span&gt;obsidian&lt;span class="se"&gt;\p&lt;/span&gt;lugins&lt;span class="se"&gt;\s&lt;/span&gt;ynthadoc&lt;span class="se"&gt;\"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in Obsidian: fully quit and reopen, then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Settings → Community plugins → Synthadoc → Enable&lt;/strong&gt;, set Server URL to &lt;code&gt;http://127.0.0.1:7070&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settings → Community plugins → Browse → search "Dataview" → Install → Enable&lt;/strong&gt; (required for the live dashboard)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full configuration reference is in &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/design.md#coding-tool-cli-providers--no-api-key-needed" rel="noopener noreferrer"&gt;docs/design.md - Coding tool CLI providers&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Else Is in v0.3.0
&lt;/h2&gt;

&lt;p&gt;The CLI provider work is one piece of a larger release. v0.3.0 also ships:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;YouTube video ingestion&lt;/strong&gt; - paste a URL, get a structured wiki page with executive summary and &lt;code&gt;[MM:SS]&lt;/code&gt; timestamped transcript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web search fan-out&lt;/strong&gt; - one search query decomposes into sub-questions, ingests multiple sources, builds cross-references automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CJK multilingual support&lt;/strong&gt; - Chinese, Japanese, and Korean queries no longer trigger false knowledge-gap reports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge gap detection hardening&lt;/strong&gt; - signal 5 redesigned for deterministic multi-aspect query scoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek provider&lt;/strong&gt; - eighth provider, OpenAI-compatible, very low cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full release notes: &lt;a href="https://github.com/axoviq-ai/synthadoc/releases/tag/v0.3.0" rel="noopener noreferrer"&gt;github.com/axoviq-ai/synthadoc/releases/tag/v0.3.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Synthadoc is open source under AGPL-3.0 at &lt;a href="https://github.com/axoviq-ai/synthadoc" rel="noopener noreferrer"&gt;github.com/axoviq-ai/synthadoc&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you are already using Claude Code or Opencode daily, the marginal cost of running a structured personal wiki on top of the same subscription is zero. The marginal benefit compounds over time. That is a trade worth making.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Synthadoc: From YouTube to Wiki: How v0.3.0 Turns Any Content into Structured Knowledge</title>
      <dc:creator>Paul Chen</dc:creator>
      <pubDate>Mon, 04 May 2026 19:10:00 +0000</pubDate>
      <link>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-from-youtube-to-wiki-how-v030-turns-any-content-into-structured-knowledge-4l38</link>
      <guid>https://dev.to/paul_chen_90371fe7426cb44/synthadoc-from-youtube-to-wiki-how-v030-turns-any-content-into-structured-knowledge-4l38</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficenc67hvtxdxuqc6yso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficenc67hvtxdxuqc6yso.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have a YouTube playlist of 40 conference talks. You have bookmarked 200 web articles. You have a folder of PDFs you keep meaning to read.&lt;/p&gt;

&lt;p&gt;None of that is knowledge yet. It is a queue.&lt;/p&gt;

&lt;p&gt;Synthadoc v0.3.0 drains the queue.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem with "Saving" Things
&lt;/h2&gt;

&lt;p&gt;Most people have a system for collecting information. Bookmarks, Notion pages, Pocket, starred emails. The collection grows. The retrieval never quite works. You remember you saved something about transformer attention mechanisms six months ago but cannot find it. You watch a 45-minute conference talk, absorb maybe 30% of it, and have no structured record of the rest.&lt;/p&gt;

&lt;p&gt;The issue is not storage. It is synthesis. Saving a link preserves a pointer. It does not extract the claim, connect it to what you already know, or surface the contradiction with something you read last week.&lt;/p&gt;

&lt;p&gt;Synthadoc v0.1.0 solved this for documents - PDFs, Word files, spreadsheets, images. v0.2.0 added hybrid BM25 + vector search so retrieval stayed sharp as the wiki grew. v0.3.0 extends the ingest surface to the two sources where most knowledge actually lives in 2026: &lt;strong&gt;video&lt;/strong&gt; and &lt;strong&gt;the live web&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ingesting a YouTube Video
&lt;/h2&gt;

&lt;p&gt;The workflow is a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc ingest &lt;span class="s2"&gt;"https://www.youtube.com/watch?v=dQw4w9WgXcQ"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or from Obsidian: open the &lt;strong&gt;Ingest: from URL...&lt;/strong&gt; modal, paste the YouTube link, press Ingest.&lt;/p&gt;

&lt;p&gt;What happens next:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Synthadoc fetches the video's caption track - no audio download, no third-party transcription API, no API key required.&lt;/li&gt;
&lt;li&gt;The transcript is chunked with embedded &lt;code&gt;[MM:SS]&lt;/code&gt; timestamps preserved so every claim is traceable to a specific moment in the video.&lt;/li&gt;
&lt;li&gt;The LLM generates an &lt;strong&gt;executive summary&lt;/strong&gt;: what the video is about, the main topics covered, and the key takeaway - in three to five sentences.&lt;/li&gt;
&lt;li&gt;The full timestamped transcript follows the summary in the wiki page.&lt;/li&gt;
&lt;li&gt;Cross-references to existing wiki pages are built automatically during ingest. If your wiki already has a page on "attention mechanisms" and the video mentions it, a &lt;code&gt;[[attention-mechanisms]]&lt;/code&gt; wikilink appears in the new page.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpltn6m04pf84739x0gj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpltn6m04pf84739x0gj.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1 — The YouTube ingest pipeline. One URL in; a structured, cross-referenced wiki page out.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;The result is a wiki page that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Illustrated&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Transformer"&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;active&lt;/span&gt;
&lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;medium&lt;/span&gt;
&lt;span class="na"&gt;created&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-05-03T14:22:01&lt;/span&gt;
&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;youtube.com/watch&lt;/span&gt;&lt;span class="pi"&gt;?&lt;/span&gt;&lt;span class="nv"&gt;v=...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gs"&gt;**Executive summary:**&lt;/span&gt; Jay Alammar's visual walkthrough of the Transformer
architecture. Covers self-attention, multi-head attention, positional
encoding, and the encoder-decoder structure using animated diagrams.
Key takeaway: the attention mechanism allows each token to "look at" every
other token in the sequence simultaneously, which is what enables parallelism
over RNNs.
&lt;span class="p"&gt;
---
&lt;/span&gt;
[00:42] The problem with sequence models is that they process tokens
one at a time, making parallelisation during training difficult...

[03:15] Self-attention computes a weighted sum of all values in the
sequence. The weights come from a compatibility function between
a query and all keys...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No manual work. The video is now part of your wiki.&lt;/p&gt;




&lt;h2&gt;
  
  
  Web Search Fan-Out
&lt;/h2&gt;

&lt;p&gt;The YouTube capability sits alongside a web search feature that works differently from a standard web search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc ingest &lt;span class="s2"&gt;"search for: transformer attention mechanisms 2025"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Synthadoc does not return ten blue links. It:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Decomposes the query into 3–5 sub-questions covering different facets of the topic.&lt;/li&gt;
&lt;li&gt;Searches the web for each sub-question independently.&lt;/li&gt;
&lt;li&gt;Ingests the top results for each, synthesizing each source into a wiki page.&lt;/li&gt;
&lt;li&gt;Builds cross-references across all the newly created pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A single web search command can add eight to fifteen structured pages to your wiki in one operation. The result is not a reading list - it is synthesized knowledge, cross-referenced and ready to query.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Timestamps Matter
&lt;/h2&gt;

&lt;p&gt;One detail worth pausing on: the &lt;code&gt;[MM:SS]&lt;/code&gt; timestamps in the transcript are not decoration.&lt;/p&gt;

&lt;p&gt;When you later ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;synthadoc query &lt;span class="s2"&gt;"what did the transformer paper say about positional encoding?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The answer includes the source citation. Because the timestamp is embedded in the page body, the citation points not just to the video but to the &lt;em&gt;moment&lt;/em&gt; in the video. You can verify the claim in thirty seconds by jumping to that timestamp.&lt;/p&gt;

&lt;p&gt;This is the same principle that makes citations in academic papers useful. The claim is not just "somewhere in this source." It is traceable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Ingest Surface in v0.3.0
&lt;/h2&gt;

&lt;p&gt;With v0.3.0, Synthadoc can ingest from the following source types in a single unified pipeline:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PDF, Word, XLSX, CSV, TXT&lt;/td&gt;
&lt;td&gt;Direct file extraction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Images (PNG, JPG, WEBP, etc.)&lt;/td&gt;
&lt;td&gt;Vision LLM extracts text and structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web pages and articles&lt;/td&gt;
&lt;td&gt;URL fetch + synthesis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YouTube videos&lt;/td&gt;
&lt;td&gt;Caption extraction + executive summary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web search results&lt;/td&gt;
&lt;td&gt;Multi-query fan-out + synthesis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PowerPoint / presentations&lt;/td&gt;
&lt;td&gt;Slide text extraction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every source type produces the same output: a structured Markdown wiki page with frontmatter, wikilinks to related pages, and a traceable source reference.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4d2aqxp61w30z9dl86o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4d2aqxp61w30z9dl86o.png" alt=" " width="800" height="1421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2 — Every source type feeds the same pipeline. The wiki grows; the query quality compounds.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Wiki Looks Like After 30 Days
&lt;/h2&gt;

&lt;p&gt;The compounding effect is the real story. After 30 days of normal usage — ingesting the things you would have saved anyway - a Synthadoc wiki typically contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;50–150 pages&lt;/strong&gt; covering your domain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic cross-references&lt;/strong&gt; linking related concepts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contradiction flags&lt;/strong&gt; where two sources disagree (Synthadoc surfaces these, you resolve them)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orphan detection&lt;/strong&gt; for pages no other page links to yet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full audit trail&lt;/strong&gt; of what was ingested, when, and at what cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 50th query to this wiki is dramatically smarter than the first, because every previous ingest has built the structure the query runs against.&lt;/p&gt;

&lt;p&gt;That is the core idea from v0.1.0, still true - but now the inputs include everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Clone and install&lt;/span&gt;
git clone https://github.com/axoviq-ai/synthadoc.git
&lt;span class="nb"&gt;cd &lt;/span&gt;synthadoc
pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Set an API key&lt;/strong&gt; — Gemini Flash is the default (free tier, 1M tokens/day, no credit card).&lt;br&gt;
Get a key at &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;aistudio.google.com/app/apikey&lt;/a&gt;, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS / Linux&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AIza…

&lt;span class="c"&gt;# Windows&lt;/span&gt;
&lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AIza…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No API key? If you already have Claude Code or Opencode, set &lt;code&gt;provider = "claude-code"&lt;/code&gt; in your wiki's &lt;code&gt;config.toml&lt;/code&gt; instead - see &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/design.md#coding-tool-cli-providers--no-api-key-needed" rel="noopener noreferrer"&gt;docs/design.md&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 3. Install the demo wiki&lt;/span&gt;
&lt;span class="c"&gt;# Linux / macOS&lt;/span&gt;
synthadoc &lt;span class="nb"&gt;install &lt;/span&gt;history-of-computing &lt;span class="nt"&gt;--target&lt;/span&gt; ~/wikis &lt;span class="nt"&gt;--demo&lt;/span&gt;

&lt;span class="c"&gt;# Windows&lt;/span&gt;
synthadoc &lt;span class="nb"&gt;install &lt;/span&gt;history-of-computing &lt;span class="nt"&gt;--target&lt;/span&gt; %USERPROFILE%&lt;span class="se"&gt;\w&lt;/span&gt;ikis &lt;span class="nt"&gt;--demo&lt;/span&gt;

&lt;span class="c"&gt;# 4. Set as the active wiki (no -w needed from here on)&lt;/span&gt;
synthadoc use history-of-computing

&lt;span class="c"&gt;# 5. Start the engine&lt;/span&gt;
synthadoc serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Install the Obsidian plugin&lt;/strong&gt; — from the cloned &lt;code&gt;synthadoc/&lt;/code&gt; repo directory, copy the pre-built plugin into your vault:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux / macOS (run from the synthadoc/ repo root)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/synthadoc   &lt;span class="c"&gt;# or wherever you cloned it&lt;/span&gt;
&lt;span class="nv"&gt;vault&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/wikis/history-of-computing
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$vault&lt;/span&gt;&lt;span class="s2"&gt;/.obsidian/plugins/synthadoc"&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;obsidian-plugin/main.js obsidian-plugin/manifest.json &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$vault&lt;/span&gt;&lt;span class="s2"&gt;/.obsidian/plugins/synthadoc/"&lt;/span&gt;

&lt;span class="c"&gt;# Windows (cmd.exe — run from the synthadoc\ repo root)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; %USERPROFILE%&lt;span class="se"&gt;\s&lt;/span&gt;ynthadoc
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="s2"&gt;"%USERPROFILE%&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="s2"&gt;ikis&lt;/span&gt;&lt;span class="se"&gt;\h&lt;/span&gt;&lt;span class="s2"&gt;istory-of-computing&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;obsidian&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;lugins&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;ynthadoc"&lt;/span&gt;
copy obsidian-plugin&lt;span class="se"&gt;\m&lt;/span&gt;ain.js &lt;span class="s2"&gt;"%USERPROFILE%&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="s2"&gt;ikis&lt;/span&gt;&lt;span class="se"&gt;\h&lt;/span&gt;&lt;span class="s2"&gt;istory-of-computing&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;obsidian&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;lugins&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;ynthadoc&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
copy obsidian-plugin&lt;/span&gt;&lt;span class="se"&gt;\m&lt;/span&gt;&lt;span class="s2"&gt;anifest.json "&lt;/span&gt;%USERPROFILE%&lt;span class="se"&gt;\w&lt;/span&gt;ikis&lt;span class="se"&gt;\h&lt;/span&gt;istory-of-computing&lt;span class="se"&gt;\.&lt;/span&gt;obsidian&lt;span class="se"&gt;\p&lt;/span&gt;lugins&lt;span class="se"&gt;\s&lt;/span&gt;ynthadoc&lt;span class="se"&gt;\"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in Obsidian: fully quit and reopen Obsidian, then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Settings → Community plugins → Synthadoc → Enable&lt;/strong&gt;, set Server URL to &lt;code&gt;http://127.0.0.1:7070&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settings → Community plugins → Browse → search "Dataview" → Install → Enable&lt;/strong&gt; (required for the live dashboard)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 7. Ingest a YouTube video&lt;/span&gt;
synthadoc ingest &lt;span class="s2"&gt;"https://www.youtube.com/watch?v=YOUR_VIDEO_ID"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Synthadoc is open source under AGPL-3.0. The full quick-start guide, architecture docs, and demo wiki are at &lt;a href="https://github.com/axoviq-ai/synthadoc" rel="noopener noreferrer"&gt;github.com/axoviq-ai/synthadoc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;👉 README: &lt;a href="https://github.com/axoviq-ai/synthadoc#readme" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc#readme&lt;/a&gt;&lt;br&gt;
👉 Quick-start guide: &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/user-quick-start-guide.md" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc/blob/main/docs/user-quick-start-guide.md&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;*Synthadoc v0.3.0 also ships CJK multilingual query support, knowledge gap detection hardening, a DeepSeek provider, and coding tool CLI providers (Claude Code, Opencode) - no separate API key needed if you already have a coding tool subscription. Full release notes in &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/design.md" rel="noopener noreferrer"&gt;docs/design.md&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Synthadoc: Beyond Keyword Search -How Combines BM25 and Vector Search to Build a Smarter Domain Wiki</title>
      <dc:creator>Paul Chen</dc:creator>
      <pubDate>Mon, 27 Apr 2026 00:21:34 +0000</pubDate>
      <link>https://dev.to/paul_chen_90371fe7426cb44/beyond-keyword-search-how-synthadoc-v020-combines-bm25-and-vector-search-to-build-a-smarter-43l7</link>
      <guid>https://dev.to/paul_chen_90371fe7426cb44/beyond-keyword-search-how-synthadoc-v020-combines-bm25-and-vector-search-to-build-a-smarter-43l7</guid>
      <description>&lt;h1&gt;
  
  
  What is Synthadoc?
&lt;/h1&gt;

&lt;p&gt;Synthadoc is an open-source, LLM-powered wiki engine. Point it at your&lt;br&gt;
organisation's documents - PDFs, PPTX, spreadsheets, DOCX, images, or web pages - and it builds a persistent, structured knowledge base your team can query, audit, and extend over time.&lt;/p&gt;

&lt;p&gt;Unlike general-purpose RAG pipelines that retrieve raw chunks at query time and discard results afterwards, Synthadoc compiles knowledge at ingest time into a living wiki that grows smarter and more consistent with every new source. The core lifecycle is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ingest: extract and synthesise facts from any source format (PDF,
XLSX, PNG, web URL)&lt;/li&gt;
&lt;li&gt;Detect: flag contradictions with existing pages and quarantine them
for review&lt;/li&gt;
&lt;li&gt;Link: connect related pages and surface knowledge gaps&lt;/li&gt;
&lt;li&gt;Query: answer questions with hybrid BM25 + optional vector search, citing the pages used&lt;/li&gt;
&lt;li&gt;Lint: resolve contradictions and surface orphan pages for human or
automated action&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Synthadoc is designed for organisations that need domain-specific, auditable knowledge management: legal teams tracking regulatory&lt;br&gt;
precedent, financial analysts maintaining market research, engineering&lt;br&gt;
groups documenting system behaviour, and research teams building&lt;br&gt;
institutional memory that persists beyond individual contributors.&lt;/p&gt;

&lt;p&gt;Synthadoc v0.2.0 is released last week, it scales seamlessly while maintaining accuracy through autonomous self-optimization.&lt;/p&gt;

&lt;p&gt;👉 Synthadoc GitHub: &lt;a href="https://github.com/axoviq-ai/synthadoc" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Most LLM knowledge tools take one of two approaches to retrieval: pure keyword search (fast but vocabulary-dependent) or pure vector/semantic search (flexible but resource-intensive). In practice, both have meaningful blind spots.&lt;/p&gt;

&lt;p&gt;Synthadoc v0.2.0 ships a hybrid retrieval pipeline that uses BM25 as a fast, precise first-pass filter and optional vector re-ranking as a semantic second pass. The result is a system that is accurate on exact-match queries, robust on paraphrased or conceptual queries, and fast enough to run on a laptop with no cloud dependency.&lt;/p&gt;

&lt;p&gt;This post explains how each technique works, where each one falls short alone, why the hybrid matters for a persistent domain wiki, and how Synthadoc v0.2.0 layers query decomposition and knowledge gap detection on top.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Is BM25?
&lt;/h1&gt;

&lt;p&gt;BM25 (Best Match 25) is a probabilistic ranking function. It scores a page relative to a query by counting how often query terms appear in the page, discounting terms that appear in almost every page, and penalising very long pages for artificially inflated counts. BM25 is the retrieval backbone of Elasticsearch, Lucene, and most production search systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scoring intuition
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegaoeg5kyikmfkmz5481.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegaoeg5kyikmfkmz5481.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where BM25 falls short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Vocabulary mismatch: query says "contributions", page says "pioneered". Score: near zero.&lt;/li&gt;
&lt;li&gt;Synonyms: "ML" and "machine learning" are different tokens.&lt;/li&gt;
&lt;li&gt;Conceptual distance: "reasoning under uncertainty" and "probabilistic inference" are semantically identical but lexically distant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a domain wiki ingested from diverse sources (papers, docs, blog posts, PDFs), the same concept will be described in many different vocabularies. BM25 alone misses a meaningful fraction of relevant pages.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Is Vector Search?
&lt;/h1&gt;

&lt;p&gt;Vector (semantic) search encodes text into dense numerical embeddings using a neural language model. Semantically similar texts land close together in that high-dimensional space regardless of surface wording. Similarity is measured as cosine distance between the query vector and each page vector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedding intuition
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakwlpeoe9thsuu831zza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakwlpeoe9thsuu831zza.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The two sentences share almost no keywords, but their vectors point in nearly the same direction because the model understands they describe the same concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where vector search falls short alone
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cold-start penalty: embedding thousands of pages takes time and compute; BM25 is instant.&lt;/li&gt;
&lt;li&gt;Exact-match dilution: specific product names or identifiers can be blurred by semantic proximity.&lt;/li&gt;
&lt;li&gt;Domain drift: general-purpose models may not distinguish highly specific domain terminology.&lt;/li&gt;
&lt;li&gt;Resource requirement: needs a model (~130 MB for bge-small-en-v1.5) and inference at query time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  BM25 vs. Vector Search: Side-by-Side
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;BM25&lt;/th&gt;
&lt;th&gt;Vector / Semantic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Matching strategy&lt;/td&gt;
&lt;td&gt;Matching strategy Exact term overlap (TF x IDF)&lt;/td&gt;
&lt;td&gt;Semantic similarity (cosine distance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vocabulary required&lt;/td&gt;
&lt;td&gt;Query words must appear in page&lt;/td&gt;
&lt;td&gt;Paraphrases and synonyms handled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed&lt;/td&gt;
&lt;td&gt;Microseconds -- no model needed&lt;/td&gt;
&lt;td&gt;Milliseconds -- model inference required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup cost&lt;/td&gt;
&lt;td&gt;Zero -- pure algorithm&lt;/td&gt;
&lt;td&gt;~130 MB model download (one-time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exact-match queries&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synonym / paraphrase&lt;/td&gt;
&lt;td&gt;Often misses&lt;/td&gt;
&lt;td&gt;Handles well&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain terminology&lt;/td&gt;
&lt;td&gt;Good if terms match&lt;/td&gt;
&lt;td&gt;Depends on model training&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interpretability&lt;/td&gt;
&lt;td&gt;Score is explainable&lt;/td&gt;
&lt;td&gt;Black-box similarity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Known vocabulary, structured content&lt;/td&gt;
&lt;td&gt;Conceptual queries, diverse sources&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  How Synthadoc Combines Both
&lt;/h1&gt;

&lt;p&gt;Synthadoc uses a hybrid pipeline where BM25 and vector search are not alternatives - they are sequential layers. BM25 does the heavy filtering; vector re-ranks the survivors.&lt;/p&gt;

&lt;h2&gt;
  
  
  The retrieval pipeline
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4ydqh6gcu86b8ffu8qp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4ydqh6gcu86b8ffu8qp.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Query decomposition: why it matters for retrieval
&lt;/h2&gt;

&lt;p&gt;Before any search happens, Synthadoc v0.2.0 breaks compound questions into focused sub-questions via an LLM call. Each sub-question runs its own BM25 (and vector) search in parallel. Results are merged by best score per page before synthesis. One complex query can retrieve from multiple distinct parts of the wiki simultaneously.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Example: Query: "Compare Turing's contributions with Von Neumann's &lt;br&gt;
architecture"&lt;br&gt;
-&amp;gt; Decomposed: ["Turing contributions computing"] | ["Von Neumann &lt;br&gt;
architecture design"]&lt;br&gt;
-&amp;gt; Two parallel BM25 searches -&amp;gt; merged candidates -&amp;gt; one synthesised&lt;br&gt;
answer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Knowledge gap detection
&lt;/h2&gt;

&lt;p&gt;After retrieval, Synthadoc evaluates three independent signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fewer than 3 pages retrieved - the wiki barely covers the topic&lt;/li&gt;
&lt;li&gt;Max BM25 score below configurable threshold (default: 2.0) - weak keyword overlap&lt;/li&gt;
&lt;li&gt;Fewer than 2 candidates contain key nouns from the question - off-topic matches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a gap fires, Synthadoc generates targeted web search suggestions and surfaces them as an Obsidian callout or CLI tip, creating a feedback loop that makes the wiki progressively denser over time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Practical Examples in Synthadoc
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Example 1: BM25 exact match (no vector needed)
&lt;/h2&gt;

&lt;p&gt;Wiki page: "Alan Turing - Enigma and the Bombe Machine"&lt;/p&gt;

&lt;p&gt;Query: "Bombe machine Enigma decryption"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;BM25 succeeds: BM25 score: HIGH - "Bombe", "machine", "Enigma", &lt;br&gt;
"decryption" all present.&lt;br&gt;
Result: page retrieved correctly. Vector re-ranking not required.`**&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Example 2: BM25 misses, vector rescues
&lt;/h2&gt;

&lt;p&gt;Wiki page: "Alan Turing - Theoretical Foundations of Modern Computers"&lt;/p&gt;

&lt;p&gt;Query: "What were Turing's contributions to computing?"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;BM25 misses, Vector rescues: BM25 score: LOW - "contributions" and &lt;br&gt;
"computing" absent from the page.&lt;br&gt;
Vector cosine score: HIGH - embeddings are semantically close.&lt;br&gt;
Result: page retrieved correctly after re-ranking. BM25 alone would have &amp;gt; missed it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Example 3: Knowledge gap fires, ingest suggestion generated
&lt;/h2&gt;

&lt;p&gt;Wiki: finance domain. Query: "What is the impact of quantitative easing on inflation?"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Gap detected: BM25: 1 page returned, score 0.8 (below threshold 2.0) &lt;br&gt;
Knowledge gap detected. Synthadoc generates:&lt;br&gt;
synthadoc ingest "search for: quantitative easing inflation impact" -w finance-wiki&lt;br&gt;
synthadoc ingest "search for: central bank monetary policy effects" -w finance-wiki&lt;br&gt;
After ingest and re-query: 7 pages returned, fully synthesised answer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Enabling Vector Search in Synthadoc
&lt;/h1&gt;

&lt;p&gt;BM25 is the default - zero setup, zero dependencies. To add vector re-ranking:&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install fastembed
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pip install fastembed&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Enable in config
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;[search]&lt;br&gt;
vector = true&lt;br&gt;
vector_top_candidates = 20 # BM25 pool size before re-ranking&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Restart the server
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;synthadoc serve -w my-wiki&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On first start, Synthadoc downloads BAAI/bge-small-en-v1.5 (~130 MB) once and embeds existing pages in the background. BM25 stays active throughout - no downtime. If the model is unavailable, the system falls back to BM25 silently.&lt;/p&gt;

&lt;h1&gt;
  
  
  Synthadoc v0.2.0: Full Feature Summary
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Query decomposition&lt;/td&gt;
&lt;td&gt;Compound questions split into parallel BM25 sub-queries, merged before synthesis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vector re-ranking&lt;/td&gt;
&lt;td&gt;Opt-in semantic re-ranking (BAAI/bge-small-en-v1.5 via fastembed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge gap detection&lt;/td&gt;
&lt;td&gt;3-signal gap check; auto-generates targeted ingest suggestions as Obsidian callout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web search decomposition&lt;/td&gt;
&lt;td&gt;Broad search topics split into focused Tavily queries; URL deduplication and cap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-model cost tracking&lt;/td&gt;
&lt;td&gt;Per-token rate table; ingest + query cost in audit.db, CLI, and Obsidian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query audit trail&lt;/td&gt;
&lt;td&gt;Full query history with sub-question count, tokens, cost, timestamp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Obsidian live web search view&lt;/td&gt;
&lt;td&gt;Real-time polling panel: phase, pages created, URL errors as fan-out completes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8 new Obsidian commands&lt;/td&gt;
&lt;td&gt;15 commands total: lint, auto-resolve, job retry/purge, audit history, scaffold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MiniMax support&lt;/td&gt;
&lt;td&gt;M2.5/M2.7 reasoning models with reasoning_content fallback for structured output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate-limit requeue&lt;/td&gt;
&lt;td&gt;429 responses requeue job (retry budget preserved); fail-fast on daily quota&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job crash recovery&lt;/td&gt;
&lt;td&gt;in_progress jobs at shutdown auto-reset to pending on next startup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bulk job cancel&lt;/td&gt;
&lt;td&gt;Cancel all pending jobs in one operation via CLI or API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  How Synthadoc Compares to Alternatives
&lt;/h1&gt;

&lt;p&gt;Most LLM knowledge tools are general-purpose RAG pipelines that retrieve raw chunks at query time with no persistent synthesis. Synthadoc compiles knowledge at ingest time, maintains a living wiki, and is designed for domain-specific, auditable deployments.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Synthadoc v0.2.0&lt;/th&gt;
&lt;th&gt;LlamaIndex / LangChain&lt;/th&gt;
&lt;th&gt;Notion AI&lt;/th&gt;
&lt;th&gt;Obsidian Copilot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ingest-time synthesis&lt;/td&gt;
&lt;td&gt;Compiled wiki&lt;/td&gt;
&lt;td&gt;Raw chunks at query time&lt;/td&gt;
&lt;td&gt;Page-level only&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain scope filtering&lt;/td&gt;
&lt;td&gt;purpose.md&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-model support&lt;/td&gt;
&lt;td&gt;6 providers&lt;/td&gt;
&lt;td&gt;Many providers&lt;/td&gt;
&lt;td&gt;OpenAI only&lt;/td&gt;
&lt;td&gt;OpenAI / Ollama&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit trail&lt;/td&gt;
&lt;td&gt;Full SQLite audit&lt;/td&gt;
&lt;td&gt;None built-in&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost tracking&lt;/td&gt;
&lt;td&gt;Per-token, per-op&lt;/td&gt;
&lt;td&gt;Manual / callback&lt;/td&gt;
&lt;td&gt;Opaque&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Offline / local&lt;/td&gt;
&lt;td&gt;Fully local&lt;/td&gt;
&lt;td&gt;Depends on provider&lt;/td&gt;
&lt;td&gt;Cloud only&lt;/td&gt;
&lt;td&gt;Ollama&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Obsidian-native output&lt;/td&gt;
&lt;td&gt;Wikilinks, Dataview&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Notion-only&lt;/td&gt;
&lt;td&gt;Read-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP API + MCP server&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;Manual wiring&lt;/td&gt;
&lt;td&gt;Proprietary API&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contradiction detection&lt;/td&gt;
&lt;td&gt;Automated&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query decomposition&lt;/td&gt;
&lt;td&gt;Parallel BM25&lt;/td&gt;
&lt;td&gt;Manual chains&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge gap detection&lt;/td&gt;
&lt;td&gt;Auto-suggestions&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensible skills&lt;/td&gt;
&lt;td&gt;Drop-in folders&lt;/td&gt;
&lt;td&gt;Custom loaders&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Licence&lt;/td&gt;
&lt;td&gt;AGPL-3.0 open source&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;Proprietary SaaS&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Enterprise and Domain-Specific Readiness
&lt;/h1&gt;

&lt;p&gt;Synthadoc is built for organisations that need a knowledge system they control, audit, and deploy into existing infrastructure - not a SaaS black box.&lt;/p&gt;

&lt;p&gt;Concrete use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Legal - track regulatory updates, case precedents, and compliance requirements across jurisdictions. New ruling ingested, old page flagged contradicted, compliance team reviews.&lt;/li&gt;
&lt;li&gt;Finance - build a living market research wiki from analyst reports, earnings calls, and regulatory filings. Query with natural language, get cited answers with full audit trail.&lt;/li&gt;
&lt;li&gt;Engineering - maintain a persistent runbook that absorbs incident post-mortems, architecture decision records, and API docs. Contradiction detection prevents stale documentation from accumulating.&lt;/li&gt;
&lt;li&gt;Research - aggregate papers, datasets, and notes into a structured knowledge base. Knowledge gap detection surfaces what the team does not yet know and generates targeted ingest suggestions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Domain specificity
&lt;/h2&gt;

&lt;p&gt;Every wiki defines its own scope via purpose.md. The LLM reads this before every ingest decision and rejects out-of-scope sources cleanly. A legal wiki does not absorb marketing copy. A financial wiki does not absorb engineering runbooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auditability
&lt;/h2&gt;

&lt;p&gt;Every ingest, query, contradiction detection, and auto-resolution is written to an append-only SQLite audit trail with token counts, cost, timestamps, and page-level actions -- all queryable from the CLI or Obsidian audit commands.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;synthadoc audit history -w my-wiki # ingest records&lt;/p&gt;

&lt;p&gt;synthadoc audit cost -w my-wiki # token spend breakdown&lt;/p&gt;

&lt;p&gt;synthadoc audit events -w my-wiki # contradiction, gate, resolution&lt;br&gt;
events&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Product and grid readiness
&lt;/h2&gt;

&lt;p&gt;Synthadoc exposes the same operations across four surfaces sharing a single agent and storage layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI: for operators, automation scripts, and CI pipelines&lt;/li&gt;
&lt;li&gt;HTTP REST API: for product integrations and custom front-ends&lt;/li&gt;
&lt;li&gt;MCP server: for direct agent-to-agent communication&lt;/li&gt;
&lt;li&gt;Obsidian plugin: for knowledge workers doing active research&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hook scripts fire on lifecycle events (on_ingest_complete, on_lint_complete), enabling event-driven automation: post a Slack summary when ingest completes, trigger a downstream build when a key page changes, or chain into a broader orchestration pipeline. Cron scheduling is built in, and multi-wiki isolation means each team or domain runs on its own port with its own audit trail.&lt;/p&gt;

&lt;h1&gt;
  
  
  Synthadoc in Agentic Autonomous Systems
&lt;/h1&gt;

&lt;p&gt;Synthadoc is purpose-built to serve as the persistent knowledge layer for LLM agent systems. Where an agent's context window is ephemeral and limited, Synthadoc's wiki is persistent, structured, and queryable -it gives agents a long-term memory that survives across sessions, scales to millions of tokens of accumulated knowledge, and is fully auditable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent integration via MCP
&lt;/h2&gt;

&lt;p&gt;The built-in MCP (Model Context Protocol) server exposes ingest, query, and lint as native tool calls. An agent running in any MCP-compatible host - Claude, GPT-4o, a custom LangChain pipeline - can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call query to retrieve cited, synthesised answers from accumulated knowledge before acting&lt;/li&gt;
&lt;li&gt;Call ingest to push new findings, research results, or external documents back into the wiki&lt;/li&gt;
&lt;li&gt;Call lint to check for contradictions introduced by new data before committing to a decision&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Event-driven agent pipelines
&lt;/h2&gt;

&lt;p&gt;Hook scripts fire on lifecycle events and can trigger downstream agent actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on_ingest_complete: a downstream agent reads newly created pages
and decides whether to trigger follow-up ingests or alert a human
reviewer&lt;/li&gt;
&lt;li&gt;on_lint_complete: an orchestrator agent receives contradiction and orphan reports and routes resolution tasks to specialised sub-agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example pipeline: a web-crawling agent ingests raw URLs; Synthadoc synthesises and deduplicates; a reporting agent queries the updated wiki and posts a daily briefing - all without human intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persistent domain memory for multi-agent systems
&lt;/h2&gt;

&lt;p&gt;In multi-agent architectures, shared knowledge is a coordination bottleneck. Synthadoc solves this by acting as a shared, structured memory store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple agents read from the same wiki via parallel HTTP queries - no shared state management required&lt;/li&gt;
&lt;li&gt;One agent's ingest results are immediately available to all agents querying the same wiki&lt;/li&gt;
&lt;li&gt;Multi-wiki isolation means separate agent clusters maintain scoped knowledge without interference&lt;/li&gt;
&lt;li&gt;The audit trail provides a complete record of which agent ingested what, when, at what cost - making multi-agent systems auditable by design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because Synthadoc is self-hosted and open-source, teams building autonomous systems retain full control over data residency, model selection, and cost - a critical requirement for enterprise agentic deployments.&lt;/p&gt;

&lt;h1&gt;
  
  
  Try Synthadoc v0.2.0
&lt;/h1&gt;

&lt;p&gt;Synthadoc v0.2.0 is available now on GitHub under the AGPL-3.0 licence. BM25 search works out of the box. Vector re-ranking is one pip install away. The Gemini free tier means you can run a full ingest-and-query cycle at zero cost.&lt;/p&gt;

&lt;p&gt;Feedback welcome: Feedback, issues, and contributions are very welcome. Open an issue on GitHub or start a discussion - the roadmap is shaped by what users need.&lt;/p&gt;

&lt;p&gt;👉 README: &lt;a href="https://github.com/axoviq-ai/synthadoc#readme" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc#readme&lt;/a&gt;&lt;br&gt;
👉 Quick-start guide: &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/user-quick-start-guide.md" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc/blob/main/docs/user-quick-start-guide.md&lt;/a&gt;&lt;br&gt;
👉 Design document: &lt;a href="https://github.com/axoviq-ai/synthadoc/blob/main/docs/design.md" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc//blob/main/docs/design.md&lt;/a&gt;&lt;br&gt;
👉 Release notes: &lt;a href="https://github.com/axoviq-ai/synthadoc/releases/tag/v0.2.0" rel="noopener noreferrer"&gt;https://github.com/axoviq-ai/synthadoc/releases/tag/v0.2.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
      <category>agentskills</category>
    </item>
  </channel>
</rss>
