<?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: specgit</title>
    <description>The latest articles on DEV Community by specgit (@specgit).</description>
    <link>https://dev.to/specgit</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4209062%2F9441d73b-96cc-4f52-a763-155e70dd7cd8.png</url>
      <title>DEV Community: specgit</title>
      <link>https://dev.to/specgit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/specgit"/>
    <language>en</language>
    <item>
      <title>Why parse-and-stringify rewrites your Obsidian notes, and how specgit keeps the bytes you didn't touch</title>
      <dc:creator>specgit</dc:creator>
      <pubDate>Mon, 26 Oct 2026 18:13:10 +0000</pubDate>
      <link>https://dev.to/specgit/why-parse-and-stringify-rewrites-your-obsidian-notes-and-how-specgit-keeps-the-bytes-you-didnt-68n</link>
      <guid>https://dev.to/specgit/why-parse-and-stringify-rewrites-your-obsidian-notes-and-how-specgit-keeps-the-bytes-you-didnt-68n</guid>
      <description>&lt;p&gt;&lt;em&gt;By the specgit team&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most of us have written this pipeline at least once. You parse a Markdown file into a syntax tree with remark, change one node, and stringify the tree back to text. For a &lt;code&gt;.canvas&lt;/code&gt; file the move is even shorter: &lt;code&gt;JSON.parse&lt;/code&gt;, mutate one object, &lt;code&gt;JSON.stringify&lt;/code&gt;. Then someone points it at a real Obsidian vault in GitHub, and the first pull request arrives as a wall of red and green.&lt;/p&gt;

&lt;p&gt;The reason is that a syntax tree records what a document means, not how it was typed. One document can be written many ways: a bullet can start with -, * or +, and emphasis can use asterisks or underscores. Once the parser has thrown those choices away, the stringifier has to make them again, and it makes them its own way on every save. Obsidian raises the stakes, because a vault is full of syntax a general Markdown tool has never heard of: callouts, wikilinks, block references, custom task statuses like &lt;code&gt;[/]&lt;/code&gt;, Dataview fields and Templater tags. A writer that doesn't know &lt;code&gt;[[Note]]&lt;/code&gt; is a link plays it safe by escaping the brackets, which is precisely what breaks the link inside Obsidian.&lt;/p&gt;

&lt;p&gt;We ran a note from our test vault through a standard Markdown writer after changing "weekly" to "daily" in one list item. Git showed eleven lines added and nine removed. The callout header became plain text, every wikilink was escaped, the tab-indented sublist came back as spaces and asterisks, and the "in progress" task stopped being a task. The board fared no better through a generic JSON writer, which deleted everything but the opening and closing braces and wrote the file back as 269 lines, so one moved card cost 301 changed lines.&lt;/p&gt;

&lt;p&gt;specgit works with Obsidian vaults by refusing to regenerate what it didn't change. When you save, every block you didn't touch is written back with its original bytes, and only the edited block goes through the writer (inside a list, only the edited item). This is the same one-word edit as specgit saves it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;gt; Ship the editor to **three pilot teams** by ==Nov 15==. See [[Launch/Risks#Top risks|top risks]] and the [[Launch/Timeline]].
&lt;span class="err"&gt;
&lt;/span&gt; ## Goals ^goals
&lt;span class="gd"&gt;-1. Three pilot teams editing weekly
&lt;/span&gt;&lt;span class="gi"&gt;+1. Three pilot teams editing daily
&lt;/span&gt; 2. Zero data-loss reports
    - Measured by support tickets
    - And by [[Launch/Metrics#^retention|retention]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hard part is proving each splice safe. Before anything is saved, specgit reads its own output back and checks that it means exactly what the editor shows, and if an edit would change how a neighboring block reads, it rewrites that neighbor too. Constructs the editor can't represent, such as bold nested inside bold, stay raw, and line endings, a byte order mark and the file's ending count as part of the file. Canvas boards get the same discipline, so moving one card changes that card's line and nothing else.&lt;/p&gt;

&lt;p&gt;All of this is held in place by 140 test files, six checks on every one of them, every CommonMark and GitHub spec example, and a harness that asks the real Obsidian app how it reads each saved note.&lt;/p&gt;

&lt;p&gt;The full post has the three-file Canvas diff before and after, how the save works, and the whole test setup: &lt;a href="https://specgit.com/blog/obsidian-fidelity" rel="noopener noreferrer"&gt;specgit.com/blog/obsidian-fidelity&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>obsidian</category>
      <category>markdown</category>
      <category>git</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
