<?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>Forem: kako-jun</title>
    <description>The latest articles on Forem by kako-jun (@kako-jun).</description>
    <link>https://forem.com/kako-jun</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%2F469969%2F73ec32e8-5ef1-4215-b269-7f0276c815b5.png</url>
      <title>Forem: kako-jun</title>
      <link>https://forem.com/kako-jun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kako-jun"/>
    <language>en</language>
    <item>
      <title>11 Languages, 14 Themes, Zero Accounts — A Calendar Image Generator for Small Businesses</title>
      <dc:creator>kako-jun</dc:creator>
      <pubDate>Sat, 07 Mar 2026 10:42:31 +0000</pubDate>
      <link>https://forem.com/kako-jun/11-languages-14-themes-zero-accounts-a-calendar-image-generator-for-small-businesses-2ed1</link>
      <guid>https://forem.com/kako-jun/11-languages-14-themes-zero-accounts-a-calendar-image-generator-for-small-businesses-2ed1</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%2Fj937w8zwbslmrmdbp4bi.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%2Fj937w8zwbslmrmdbp4bi.png" alt="11 languages, 14 themes" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Small business owners around the world post monthly calendar images on social media — "here's when we're open, here's when we're closed."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://3min.llll-ll.com" rel="noopener noreferrer"&gt;&lt;strong&gt;3 min. Calendar&lt;/strong&gt;&lt;/a&gt; generates these images in your browser. No account. No server. No tracking.&lt;/p&gt;

&lt;p&gt;It now supports &lt;strong&gt;11 languages&lt;/strong&gt; with localized holidays, and &lt;strong&gt;14 color themes&lt;/strong&gt; to match your brand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Already in use
&lt;/h2&gt;

&lt;p&gt;A guesthouse in Noto, Japan — &lt;a href="https://www.instagram.com/kikyoan_greengrass/" rel="noopener noreferrer"&gt;Kikyou-an&lt;/a&gt; — has been using 3 min. Calendar to post their monthly availability on Instagram.&lt;/p&gt;

&lt;p&gt;Noto was hit by a magnitude 7 earthquake in 2024. The area is still recovering. Kikyou-an reopened as a small guesthouse to support the local community — and they've been getting bookings from overseas guests.&lt;/p&gt;

&lt;p&gt;When they told us "the badge text (休, 満, etc.) is too small to read" — we made them bigger. When they said "I actually made a calendar in 3 minutes" — well, the name checks out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every language gets the same features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Holidays&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🇺🇸&lt;/td&gt;
&lt;td&gt;English&lt;/td&gt;
&lt;td&gt;US holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇯🇵&lt;/td&gt;
&lt;td&gt;日本語&lt;/td&gt;
&lt;td&gt;Japanese holidays + Rokuyo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇪🇸&lt;/td&gt;
&lt;td&gt;Español&lt;/td&gt;
&lt;td&gt;Spanish holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇫🇷&lt;/td&gt;
&lt;td&gt;Français&lt;/td&gt;
&lt;td&gt;French holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇰🇷&lt;/td&gt;
&lt;td&gt;한국어&lt;/td&gt;
&lt;td&gt;Korean holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇨🇳&lt;/td&gt;
&lt;td&gt;中文&lt;/td&gt;
&lt;td&gt;Chinese holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇧🇷&lt;/td&gt;
&lt;td&gt;Português&lt;/td&gt;
&lt;td&gt;Brazilian holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇹🇭&lt;/td&gt;
&lt;td&gt;ไทย&lt;/td&gt;
&lt;td&gt;Thai holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇻🇳&lt;/td&gt;
&lt;td&gt;Tiếng Việt&lt;/td&gt;
&lt;td&gt;Vietnamese holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇵🇭&lt;/td&gt;
&lt;td&gt;Filipino&lt;/td&gt;
&lt;td&gt;Philippine holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇳🇵&lt;/td&gt;
&lt;td&gt;नेपाली&lt;/td&gt;
&lt;td&gt;Nepali holidays&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  A few examples
&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%2Flcxnqo9ux06t9tmuyibn.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%2Flcxnqo9ux06t9tmuyibn.png" alt="English — barber shop, light theme" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;English — Joe's Barber, light theme, rounded grid&lt;/em&gt;&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%2Fazbmkgp2yjhpsplatcdt.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%2Fazbmkgp2yjhpsplatcdt.png" alt="Japanese — izakaya, dark blue theme" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;日本語 — 居酒屋ゆかり, dark blue theme with background image&lt;/em&gt;&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%2Fne6202oqebjxbax23fl4.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%2Fne6202oqebjxbax23fl4.png" alt="Korean — restaurant, light green" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;한국어 — 한라산식당, light green theme&lt;/em&gt;&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%2F53cny1jdwnpoulfruv71.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%2F53cny1jdwnpoulfruv71.png" alt="Portuguese — cafe, light blue" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Português — Café Brasil, light blue theme with Christmas&lt;/em&gt;&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%2F3oih90xph1pbbcbfibak.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%2F3oih90xph1pbbcbfibak.png" alt="Thai — restaurant, dark green" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;ไทย — ร้านอาหารไทย, dark green theme with background&lt;/em&gt;&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%2F57i8fh1rgpdo0k5ej5x5.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%2F57i8fh1rgpdo0k5ej5x5.png" alt="Nepali — kitchen, light purple" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;नेपाली — काठमाडौँ किचन, light purple theme&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://3min.llll-ll.com" rel="noopener noreferrer"&gt;3min.llll-ll.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pick your language, theme, and grid style&lt;/li&gt;
&lt;li&gt;Tap dates to set open/closed/hours&lt;/li&gt;
&lt;li&gt;Download or share the image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you use a background image, try the "Grid" (lined) style — it keeps the photo visible between cells instead of covering it with rounded boxes.&lt;/p&gt;

&lt;p&gt;Data stays in your browser. Works offline as a PWA.&lt;/p&gt;

&lt;h2&gt;
  
  
  The backstory
&lt;/h2&gt;

&lt;p&gt;I built this for my mother-in-law's earthquake-recovery guesthouse in Noto, Japan. &lt;a href="https://dev.to/kako-jun/my-mother-in-laws-post-earthquake-guesthouse-needed-a-calendar-tool-every-result-said-canva-so-i-d3n"&gt;Read the full story here.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://3min.llll-ll.com" rel="noopener noreferrer"&gt;3min.llll-ll.com&lt;/a&gt;&lt;/strong&gt; — open source on &lt;a href="https://github.com/kako-jun/3min" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article also took about 3 minutes to read. You're welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>pwa</category>
      <category>showdev</category>
      <category>smallbusiness</category>
    </item>
    <item>
      <title>I built a fetch tool that only runs on RISC-V (riscfetch v2.2.0)</title>
      <dc:creator>kako-jun</dc:creator>
      <pubDate>Mon, 16 Feb 2026 11:37:42 +0000</pubDate>
      <link>https://forem.com/kako-jun/i-built-a-fetch-tool-that-only-runs-on-risc-v-riscfetch-v220-9f1</link>
      <guid>https://forem.com/kako-jun/i-built-a-fetch-tool-that-only-runs-on-risc-v-riscfetch-v220-9f1</guid>
      <description>&lt;p&gt;&lt;em&gt;This is Part 1 of a three-part series about building, running, and trying to distribute a RISC-V tool.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Part 1 (this post)&lt;/strong&gt;: I built a fetch tool that only runs on RISC-V&lt;/li&gt;
&lt;li&gt;Part 2: I bought a SATA SSD instead of NVMe by mistake — Orange Pi RV2 review&lt;/li&gt;
&lt;li&gt;Part 3: I tried to reach China — Creating a Gitee account as a foreigner&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;I bought my first RISC-V board because I thought it was cool. Not for work. Not for a startup. I just wanted to see what a non-x86, non-ARM computer felt like.&lt;/p&gt;

&lt;p&gt;Then I ran neofetch on it.&lt;/p&gt;

&lt;p&gt;It showed me... Ubuntu. Kernel version. Uptime. RAM. The same stuff it shows on every Linux machine. Nothing about the architecture that made this board interesting in the first place.&lt;/p&gt;

&lt;p&gt;That felt wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing neofetch can't tell you
&lt;/h2&gt;

&lt;p&gt;RISC-V isn't like x86 or ARM. Those architectures ship a fixed set of instructions. You get what you get.&lt;/p&gt;

&lt;p&gt;RISC-V is modular. The base instruction set is tiny. Everything else — floating point, atomics, vector operations, cryptography — comes as extensions. Each chip vendor picks which ones to implement. It's like a skill tree in an RPG. Two RISC-V boards sitting on your desk might have completely different capabilities.&lt;/p&gt;

&lt;p&gt;When I started collecting boards — Orange Pi RV2, VisionFive 2, a Milk-V Duo — the first question I always had was: "What can this thing actually do?" Which extensions does it support? Does it have vector instructions? What's the VLEN? Which vendor's silicon is this?&lt;/p&gt;

&lt;p&gt;neofetch couldn't answer any of that. fastfetch couldn't either. They're architecture-agnostic by design, which means they treat RISC-V like just another Linux box.&lt;/p&gt;

&lt;p&gt;So I built a tool that doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real struggle: buying RISC-V boards
&lt;/h2&gt;

&lt;p&gt;Here's the thing nobody warns you about. The hard part of a RISC-V hobby isn't the code. It's getting the hardware.&lt;/p&gt;

&lt;p&gt;I've been buying boards from AliExpress, which means navigating an ecosystem that runs on its own rules. The same board shows up in five different shops at five different prices. Product titles are half in Chinese, half in machine-translated English, and the specs might or might not match reality. I've been burned on AliExpress before — fake SD cards, packages that vanished into the void — so every order comes with a little prayer.&lt;/p&gt;

&lt;p&gt;But here's the thing: every RISC-V board I've ordered has actually arrived, and worked. Maybe the RISC-V sellers are just a more honest crowd. Each board that shows up feels a little special. And the first thing I want to do when I plug one in is find out exactly what's inside.&lt;/p&gt;

&lt;h2&gt;
  
  
  riscfetch: the anti-portable tool
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/kako-jun/riscfetch" rel="noopener noreferrer"&gt;riscfetch&lt;/a&gt; is a system information tool exclusively for RISC-V. If you run it on x86 or ARM, it exits. That's intentional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most things don't run on RISC-V. So I made something that only runs on RISC-V.&lt;/strong&gt; I liked the irony.&lt;/p&gt;

&lt;p&gt;It checks &lt;strong&gt;155 ISA extensions&lt;/strong&gt; — 11 standard, 98 Z-extensions, and 46 S-extensions — organized by category: Bit Manipulation, Cryptography, Vector, Compressed, Atomics, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  v2.2.0: Automatic vendor detection
&lt;/h3&gt;

&lt;p&gt;The headline feature in v2.2.0 is automatic vendor detection. It auto-detects across 12 RISC-V vendors — SiFive, StarFive, Pine64, Milk-V, Espressif, SpacemiT, and others — so you get a personalized display with the right ASCII art logo for your hardware, without configuring anything.&lt;/p&gt;

&lt;p&gt;It also shows hart count, vector capabilities, and cache info.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--all&lt;/code&gt; flag shows checkmarks and crosses for every single extension. It's like opening the skill tree screen and seeing what's unlocked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ext:  ✓I ✗E ✓M ✓A ✓F ✓D ✗Q ✓C ✗B ✓V ✗H
Z-Bit: ✓Zba ✓Zbb ✓Zbc ✓Zbs
Z-Crypto: ✗Zbkb ✗Zbkc ✗Zbkx ✓Zk ✗Zkn ...
Z-Vector: ✓Zve32f ✓Zve32x ✓Zve64d ✓Zve64f ✓Zve64x ✓Zvfh ✓Zvfhmin ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--explain&lt;/code&gt; flag adds human-readable descriptions. Because knowing you have &lt;code&gt;Zba&lt;/code&gt; is less useful than knowing what it actually does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Zba        Address Generation
Zbb        Basic Bit Manipulation
Zbc        Carry-less Multiply
Zbs        Single-bit Operations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;--json&lt;/code&gt; gives you machine-readable output for scripts and dashboards.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; &lt;code&gt;fastfetch &amp;amp;&amp;amp; riscfetch -r&lt;/code&gt; gives you the complete picture — fastfetch for general system info, riscfetch for the RISC-V-specific stuff.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Studying the spec so you don't have to
&lt;/h2&gt;

&lt;p&gt;Supporting 155 extensions meant reading the actual RISC-V ISA specification. Not just the base spec — the ratified extensions, the draft extensions, the vendor-specific ones.&lt;/p&gt;

&lt;p&gt;The naming convention has layers. Single-letter standard extensions (I, E, M, A, F, D, Q, C, B, V, H) cover the fundamentals. Z-extensions get finer-grained — 98 of them across 10+ categories like bit manipulation (4 extensions), cryptography (8), vector (20+), compressed (5), atomics (3). Then S-extensions for supervisor-level features. The raw names — Zbkb, Zbkc, Zvfhmin — are meaningless unless you've memorized the spec. riscfetch groups them into categories and, with &lt;code&gt;--explain&lt;/code&gt;, translates them into plain language.&lt;/p&gt;

&lt;p&gt;The point isn't to memorize these. The point is that when you plug in a new board, you can run one command and see exactly what you're working with.&lt;/p&gt;

&lt;h2&gt;
  
  
  The technical bits
&lt;/h2&gt;

&lt;p&gt;riscfetch is written in Rust and split into two crates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;riscfetch-core&lt;/strong&gt;: A library crate that does the actual detection and parsing. You can use this in your own projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;riscfetch-cli&lt;/strong&gt;: The binary that formats and displays everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It reads from &lt;code&gt;/proc/cpuinfo&lt;/code&gt;, device tree nodes, and other Linux interfaces to gather RISC-V-specific information. No kernel modules, no special privileges needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  On using AI
&lt;/h2&gt;

&lt;p&gt;I'll be upfront: I built riscfetch with Claude Code. The coding, the spec research, the extension categorization — most of it was done by AI. My job was to know what I wanted, steer the direction, and verify the results on real hardware.&lt;/p&gt;

&lt;p&gt;I'm not embarrassed about that. If there are mistakes in how riscfetch parses some obscure extension, I'll fix them — or more likely, I'll retry with a smarter version of Claude and it'll get it right. That's how this works now.&lt;/p&gt;

&lt;p&gt;What I did bring was the motivation. No AI wakes up one morning and thinks "I wish neofetch showed me RISC-V extensions." That frustration was mine. The idea was mine. The boards sitting on my desk are mine. The tool just needed someone to want it to exist.&lt;/p&gt;

&lt;p&gt;I think the era of hiding AI collaboration is over. What matters is the "what" and the "why." The "how" keeps changing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most useful tool
&lt;/h2&gt;

&lt;p&gt;And I think the lesson generalizes. The most useful tool is sometimes one that goes deep on one thing instead of being shallow across everything. There was exactly zero tools that could tell you which RISC-V cryptography extensions your board supports. Now there's one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;I'll keep updating riscfetch as new boards and extensions hit the market. The RISC-V spec keeps growing, and so will this tool. Current version is 2.2.0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;riscfetch &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; riscfetch &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or grab a pre-built binary from &lt;a href="https://github.com/kako-jun/riscfetch/releases" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt;. It's MIT licensed.&lt;/p&gt;

&lt;p&gt;If you have a RISC-V board — any board — I'd love to see what riscfetch shows on it. Drop your output in the comments. I've tested on a handful of boards, but the ecosystem is diverse and I know there are configurations I haven't seen yet. RV32E systems, unusual VLEN settings, boards from vendors I haven't added logos for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/kako-jun/riscfetch" rel="noopener noreferrer"&gt;github.com/kako-jun/riscfetch&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;In Part 2, I'll walk through setting up Orange Pi RV2 with USB SSD boot and building a dev environment on RISC-V hardware.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>riscv</category>
      <category>rust</category>
      <category>linux</category>
      <category>showdev</category>
    </item>
    <item>
      <title>My mother-in-law's post-earthquake guesthouse needed a calendar tool. Every result said Canva. So I built one.</title>
      <dc:creator>kako-jun</dc:creator>
      <pubDate>Mon, 16 Feb 2026 08:29:05 +0000</pubDate>
      <link>https://forem.com/kako-jun/my-mother-in-laws-post-earthquake-guesthouse-needed-a-calendar-tool-every-result-said-canva-so-i-d3n</link>
      <guid>https://forem.com/kako-jun/my-mother-in-laws-post-earthquake-guesthouse-needed-a-calendar-tool-every-result-said-canva-so-i-d3n</guid>
      <description>&lt;p&gt;My mother-in-law's house was hit by the 2024 Noto peninsula earthquake — intensity 7, the maximum on Japan's seismic scale. She watched a mountainside collapse in front of her. The neighborhood is mostly empty lots now. As the area slowly recovers, she started running a small guesthouse to support the local community. She needed to post monthly calendars on Instagram — which days are open, which are booked, which are closed.&lt;/p&gt;

&lt;p&gt;I looked into how small businesses in Japan handle this, and fell into a rabbit hole.&lt;/p&gt;

&lt;h2&gt;
  
  
  The calendar image culture
&lt;/h2&gt;

&lt;p&gt;If you look at the Instagram accounts of small businesses in Japan — ramen shops, Indian restaurants, hair salons, guesthouses — you'll notice something: they all post monthly calendar images.&lt;/p&gt;

&lt;p&gt;Not Google Calendar embeds or booking widgets — just &lt;strong&gt;images.&lt;/strong&gt; Hand-made, posted as photos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ○ = available
 △ = few spots left
 ✕ = fully booked
 休 = closed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every month, shop owners spend time creating these images and posting them to Instagram or LINE (Japan's dominant messaging app). Their customers check these images to know when to visit.&lt;/p&gt;

&lt;p&gt;"There must be a dedicated tool for this," I thought.&lt;/p&gt;

&lt;p&gt;There wasn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "just use Canva" loop
&lt;/h2&gt;

&lt;p&gt;Search "how to make a business calendar for Instagram" in Japanese and every result says Canva. Shop owners recommend it to each other. Tutorial blogs recommend it. It's a closed loop — everyone telling everyone to use the same tool.&lt;/p&gt;

&lt;p&gt;Canva is powerful. It can probably do everything I needed. But here's what actually happens in Japan: one blogger writes a tutorial showing how to make a calendar by dragging text boxes around a canvas, aligning them manually, fighting with snap points. That tutorial gets copied. The copy gets recommended. And suddenly, that painful workflow &lt;em&gt;is&lt;/em&gt; the standard method. Nobody goes back to check if there's a better way.&lt;/p&gt;

&lt;p&gt;Japan has a culture of "right-face" (右ならえ) — once everyone lines up behind a method, it's very hard to correct course. The method becomes the answer, even if it's inefficient. I don't blame anyone for following the tutorials they found. But I also didn't feel like digging through Canva's feature set to find the "correct" way when the entire ecosystem had already settled on the wrong one.&lt;/p&gt;

&lt;p&gt;The gap between "this should be easy" and "this is what people actually do" was the real problem. Not Canva. Not the bloggers. The gap itself.&lt;/p&gt;

&lt;p&gt;So I built something to close it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rage-driven development
&lt;/h2&gt;

&lt;p&gt;I call it rage-driven development. Not anger at people. Anger at the situation. The gap between "this should be easy" and "this is needlessly hard" is fuel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://3min.llll-ll.com" rel="noopener noreferrer"&gt;3 min. Calendar&lt;/a&gt;&lt;/strong&gt; — an app that creates monthly business calendar images in about three minutes.&lt;/p&gt;

&lt;p&gt;The workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tap dates to set their status (open, closed, few spots, fully booked)&lt;/li&gt;
&lt;li&gt;Pick a color theme&lt;/li&gt;
&lt;li&gt;Export as image&lt;/li&gt;
&lt;li&gt;Post to Instagram&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No account. No sign-up. No cloud. Everything runs in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "3 minutes"
&lt;/h2&gt;

&lt;p&gt;I timed it. From opening the app to having a finished calendar image ready to post — three minutes for someone who's never seen the app before. Under two minutes once you've done it once.&lt;/p&gt;

&lt;p&gt;The name comes from Cup Noodles — invented in Japan, ready in three minutes. If instant noodles can be done in three minutes, so can a calendar. If it takes you longer, I'm sorry.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real users
&lt;/h2&gt;

&lt;p&gt;The users I built this for aren't developers. They're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A ramen shop owner who closes on Tuesdays and the third Wednesday of each month&lt;/li&gt;
&lt;li&gt;An Indian restaurant owner who speaks Nepali as a first language&lt;/li&gt;
&lt;li&gt;A guesthouse owner in a disaster recovery area — like my mother-in-law&lt;/li&gt;
&lt;li&gt;A bar owner who needs to post staff schedules for the month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These people should be focusing on their business, not learning design tools. The tool should be a black box — tap a few buttons, get an image, move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  11 languages
&lt;/h3&gt;

&lt;p&gt;Japan has a lot of small businesses run by immigrants. Indian and Nepali restaurant owners. Chinese restaurant owners cycling through lease-transfer properties. Vietnamese, Thai, Filipino workers running small shops.&lt;/p&gt;

&lt;p&gt;3 min. Calendar supports 11 languages: Japanese, English, Chinese (Simplified), Korean, Nepali, Thai, Vietnamese, Tagalog, Spanish, Portuguese, and French. The UI auto-detects your browser language.&lt;/p&gt;

&lt;p&gt;This wasn't a nice-to-have. If I'm building for small business owners in Japan, I'm building for people who might not read Japanese fluently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical decisions (for the devs)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; React 18, TypeScript, Vite, Tailwind CSS, Zustand, Konva (Canvas), i18next, Workbox&lt;/p&gt;

&lt;h3&gt;
  
  
  Why client-side only
&lt;/h3&gt;

&lt;p&gt;No server means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No hosting costs (it's on Cloudflare Pages)&lt;/li&gt;
&lt;li&gt;No privacy concerns — zero data leaves the browser&lt;/li&gt;
&lt;li&gt;Works offline as a PWA — install it on your phone, use it in a dead zone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shop owners don't have reliable internet at all times. My mother-in-law's area in Noto is a case in point — fiber was never there to begin with. It was supposed to be rolled out, but the earthquake derailed those plans. Meanwhile, ADSL service was terminated on schedule. Households were left with no fixed-line internet, forced to get by on mobile data. The app needs to work regardless.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Canvas (Konva) instead of DOM-to-image
&lt;/h3&gt;

&lt;p&gt;The exported image needs to look exactly like the preview. DOM-to-image libraries (html2canvas, dom-to-image) have cross-browser inconsistencies, font rendering differences, and can't guarantee pixel-perfect output.&lt;/p&gt;

&lt;p&gt;Konva renders directly to Canvas. What you see is what you export. No surprises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Font loading strategy
&lt;/h3&gt;

&lt;p&gt;11 languages means 11 different font families (Noto Sans JP, Noto Sans SC, Noto Sans Devanagari, etc.). Loading all of them upfront would be megabytes of wasted bandwidth.&lt;/p&gt;

&lt;p&gt;The app detects your language and loads only the font you need. If you switch languages, it lazy-loads the new font. Most users never download more than one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Holiday auto-detection
&lt;/h3&gt;

&lt;p&gt;The app auto-detects holidays for 100+ countries. A Japanese shop sees Japanese holidays pre-marked. A Thai restaurant sees Thai holidays. This saves the "wait, is next Monday a holiday?" lookup that every shop owner does every month.&lt;/p&gt;

&lt;p&gt;For Japan specifically, it also shows &lt;strong&gt;rokuyo&lt;/strong&gt; (六曜) — a traditional calendar system that some customers still care about. "Taian" (大安) is a lucky day; "Butsumetsu" (仏滅) is unlucky. Some businesses adjust their schedules around this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The QR code problem
&lt;/h2&gt;

&lt;p&gt;While building this, I discovered something that made me genuinely angry. Many small shops in Japan use free QR code generators to create codes for their Instagram or LINE pages. Some of these "free" generators use URL shorteners that can redirect to scam sites after a delay.&lt;/p&gt;

&lt;p&gt;QR codes were invented in Japan. It's a Japanese technology. And now Japanese shop owners are being redirected through that same technology to foreign scam services. A guesthouse owner who survived an earthquake, who's trying to rebuild her community, puts a QR code on her flyer — and a scam service hijacks it to redirect her guests to a phishing page. She doesn't know. Her guests don't know. She's already dealing with enough.&lt;/p&gt;

&lt;p&gt;3 min. Calendar includes a QR code generator that creates codes pointing directly to the URL you specify. No shorteners. No redirects. No intermediary services. The QR code encodes exactly what you type.&lt;/p&gt;

&lt;p&gt;It's a small feature, but I wasn't going to let that one slide.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I don't know
&lt;/h2&gt;

&lt;p&gt;I built this for the Japanese market because that's what I see every day. But I suspect this pattern — small businesses posting schedule images on social media — exists in other countries too.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the Indian restaurant near you post monthly schedules on WhatsApp?&lt;/li&gt;
&lt;li&gt;Do small shops in Southeast Asia use LINE or Zalo for this?&lt;/li&gt;
&lt;li&gt;Is this an Instagram-specific behavior, or does it happen on Facebook too?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I genuinely don't know. If you've seen this pattern in your country, I'd love to hear about it in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://3min.llll-ll.com" rel="noopener noreferrer"&gt;3min.llll-ll.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Free. No sign-up. Works on phone. Install as PWA for offline use.&lt;/p&gt;

&lt;p&gt;If you run a small business — or know someone who does — try making next month's calendar. Time yourself. If it takes more than three minutes, tell me what slowed you down.&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>react</category>
      <category>pwa</category>
      <category>showdev</category>
    </item>
    <item>
      <title>My OSS Stalled for 3 Months Because of Misguided Vibe Coding—This Is the Full Reboot Story</title>
      <dc:creator>kako-jun</dc:creator>
      <pubDate>Tue, 16 Dec 2025 06:04:23 +0000</pubDate>
      <link>https://forem.com/kako-jun/my-oss-stalled-for-3-months-because-of-misguided-vibe-coding-this-is-the-full-reboot-story-2da5</link>
      <guid>https://forem.com/kako-jun/my-oss-stalled-for-3-months-because-of-misguided-vibe-coding-this-is-the-full-reboot-story-2da5</guid>
      <description>&lt;p&gt;I'm building an open-source crate that has been downloaded about 8,000 times and is used both in Japan and the United States.&lt;/p&gt;

&lt;p&gt;Then I promoted it, realized I'd messed up, and every new star on the repo made my stomach drop.&lt;/p&gt;

&lt;p&gt;My conclusion: so-called "vibe coding" by self-proclaimed power users is a spaghetti-code factory.&lt;/p&gt;

&lt;p&gt;Instead of throwing the mess away, I decided to rebuild it into something edible. That's what this reboot is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever had a solo project that stagnated so badly you couldn't touch it for months?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;diffx&lt;/code&gt;, my structured-data diff tool, was essentially frozen from August to November 2025—about three months. It should have been "feature complete," yet I couldn't move forward. I analyzed what went wrong and brought it back using a process I now call the "reboot."&lt;/p&gt;

&lt;p&gt;This post documents everything: the root-cause analysis, the failed collaboration with AI, escaping a monorepo, and the concrete reboot steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who should read this&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solo developers stuck in a stalled project&lt;/li&gt;
&lt;li&gt;People struggling with code quality while using AI pair programmers (Claude Code, etc.)&lt;/li&gt;
&lt;li&gt;Engineers burned out by monorepos and shared CI/CD frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Is diffx?
&lt;/h3&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kako-jun" rel="noopener noreferrer"&gt;
        kako-jun
      &lt;/a&gt; / &lt;a href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;
        diffx
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;diffx&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx/README.ja.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/kako-jun/diffx/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://crates.io/crates/diffx" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/829d21876ad257091fe68d81336d0413406a4e5ff967a43c6169cb29cdd3da4a/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f64696666782e737667" alt="Crates.io"&gt;&lt;/a&gt;
&lt;a href="https://docs.rs/diffx-core" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4564626b8de103a353bbee9f74eee871eaf881ae4a1053c2bdb4dd7cb18663e9/68747470733a2f2f646f63732e72732f64696666782d636f72652f62616467652e737667" alt="docs.rs"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kako-jun/diffx/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Semantic diff tool for structured data (JSON/YAML/TOML/XML/INI/CSV). Ignores key ordering and whitespace, shows only meaningful changes.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why diffx?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Traditional &lt;code&gt;diff&lt;/code&gt; doesn't understand structure:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ diff config_v1.json config_v2.json
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt; {
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;myapp&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;version&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt; }
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; {
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;version&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;myapp&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; }&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;A simple key reordering shows every line as changed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;diffx&lt;/code&gt; shows only semantic changes:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ diffx config_v1.json config_v2.json
&lt;span class="pl-k"&gt;~&lt;/span&gt; version: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; -&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; As CLI tool&lt;/span&gt;
cargo install diffx

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; As library (Cargo.toml)&lt;/span&gt;
[dependencies]
diffx-core = &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;0.6&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Basic&lt;/span&gt;
diffx file1.json file2.json

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Output example&lt;/span&gt;
&lt;span class="pl-k"&gt;~&lt;/span&gt; version: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; -&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
+ features[0]: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;new-feature&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
- deprecated: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;old-value&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Supported Formats&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;JSON, YAML…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;diffx is a Rust tool that extracts &lt;em&gt;semantic&lt;/em&gt; diffs from structured data such as JSON, YAML, TOML, XML, INI, and CSV. Unlike classic text-based diffs, it ignores formatting and key-order changes, surfacing only meaningful changes.&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="nv"&gt;$ &lt;/span&gt;diffx config-old.yaml config-new.yaml
~ server.port: 8080 -&amp;gt; 9000
+ server.timeout: 30
- server.deprecated_option
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It's built for DevOps/SRE workflows, especially tracking Kubernetes YAML and Terraform config changes. There are also npm (diffx-js) and Python (diffx-python) editions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;crates.io: &lt;a href="https://crates.io/crates/diffx-core" rel="noopener noreferrer"&gt;https://crates.io/crates/diffx-core&lt;/a&gt; / &lt;a href="https://crates.io/crates/diffx" rel="noopener noreferrer"&gt;https://crates.io/crates/diffx&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/diffx-js" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/diffx-js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/diffx-python/" rel="noopener noreferrer"&gt;https://pypi.org/project/diffx-python/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Chapter 1: What Happened During the Freeze
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Illusion of "Done"
&lt;/h3&gt;

&lt;p&gt;Here's the post from that era:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kako-jun/i-built-diffx-a-structure-aware-ai-first-diff-tool-in-rust-lets-end-the-comma-induced-suffering-491h"&gt;https://dev.to/kako-jun/i-built-diffx-a-structure-aware-ai-first-diff-tool-in-rust-lets-end-the-comma-induced-suffering-491h&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repo picked up a ton of stars. Some people even became sponsors.&lt;/p&gt;

&lt;p&gt;On the surface the project looked polished:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;README in Japanese, English, and Chinese&lt;/li&gt;
&lt;li&gt;Support for six data formats&lt;/li&gt;
&lt;li&gt;npm and Python ports&lt;/li&gt;
&lt;li&gt;A complex CI/CD pipeline&lt;/li&gt;
&lt;li&gt;A 740-line migration plan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in reality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI/CD was broken beyond repair&lt;/li&gt;
&lt;li&gt;Tests didn't necessarily validate the real specs&lt;/li&gt;
&lt;li&gt;Docs and implementation had likely drifted apart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI technically worked, but I couldn't honestly call it sustainable.&lt;/p&gt;


&lt;h2&gt;
  
  
  Chapter 2: Root Causes of the Stagnation
&lt;/h2&gt;

&lt;p&gt;I spent those three months "studying how to make it sustainable."&lt;/p&gt;

&lt;p&gt;After analyzing diffx, I found three major failure categories.&lt;/p&gt;
&lt;h3&gt;
  
  
  Category A: Project Design Failures
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Running Three Projects at Once and Over-Sharing Everything
&lt;/h4&gt;

&lt;p&gt;Besides diffx, I had two sister projects in mind: diffai (diffs for AI model configs) and lawkit (statistics like Benford's law).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I did&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built a shared CI/CD system for all three&lt;/li&gt;
&lt;li&gt;Tried to orchestrate everything via &lt;code&gt;workflow_call&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added symbolic links to a shared repo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Outcome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I split the shared parts (GitHub workflows, scripts, etc.) into another repo, then symlinked it from each project.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/kako-jun/repos/.github/          ← shared repo
└── rust-cli-kiln/
    └── scripts/
        └── testing/
            └── quick-check.sh  ← never stabilized

Inside each project:
github-shared -&amp;gt; ../.github  ← symlink
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;quick-check.sh&lt;/code&gt; existed, but tuning it for diffx broke lawkit, and fixing lawkit broke diffai. Nothing stayed green.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: Don't think about the next project before the first one is stable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  2. Monorepo Mismanagement
&lt;/h4&gt;

&lt;p&gt;I kept the Rust core plus the npm and Python bindings in one repo.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diffx/                    # monorepo
├── diffx-core/           # Rust
├── diffx-cli/            # Rust
├── diffx-js/             # Node.js (napi-rs)
└── diffx-python/         # Python (PyO3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Problems&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Three languages/toolchains sharing one repo&lt;/li&gt;
&lt;li&gt;GitHub Actions exploding into six workflows plus the shared repo&lt;/li&gt;
&lt;li&gt;Any change risked breaking everything&lt;/li&gt;
&lt;li&gt;Releases required a multi-step ritual&lt;/li&gt;
&lt;li&gt;Dependency graphs grew exponentially complicated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Release cadence mismatch&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Minor bug fix in Rust
  → diffx-core v0.6.1
  → diffx-cli v0.6.1
  → diffx-js needs binding updates (half-day)
  → diffx-python needs similar updates (half-day)
  → Rust-only release goes out
  → Versions drift apart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  3. Writing Multilingual Docs Too Early
&lt;/h4&gt;

&lt;p&gt;I tried to ship three READMEs from day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problems&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keeping three files in sync is exhausting&lt;/li&gt;
&lt;li&gt;Every change becomes triple work&lt;/li&gt;
&lt;li&gt;You forget which file is "the truth"&lt;/li&gt;
&lt;li&gt;Everything becomes stale simultaneously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Better approach&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Phase 1: README_ja.md only (use the language you can edit fastest)
Phase 2: Add English once the project matures
Phase 3: Add other languages based on demand
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Category B: Failing to Work with AI
&lt;/h3&gt;

&lt;p&gt;I used Claude Code extensively and ran into multiple failure modes.&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Ignoring Quality Loss from Context Compression
&lt;/h4&gt;

&lt;p&gt;In sessions where context was compressed three times, the answers started perfect and degraded over time.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start: accurate, detailed implementation
  ↓ 1 hour later: subtle spec violations
  ↓ 2 hours later: obvious bugs
  ↓ 3 hours later: forgets prior instructions entirely
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Behavior when only 20% context remains&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once context gets thin, the AI openly changes personality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lies without hesitation&lt;/li&gt;
&lt;li&gt;Randomly omits code&lt;/li&gt;
&lt;li&gt;Pushes to commit even when not asked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even with a spec doc, it forgets the spec and freestyles. Beginners who trust the AI blindly fall into a slow-motion desync between spec and code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does it happen?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My guess: coding AIs are trained to "wrap up cleanly before context collapses." That's reasonable by itself.&lt;/p&gt;

&lt;p&gt;But combine that instinct with "first-year vibe coding" and you get disaster. On Qiita or Zenn you'll see excited posts: "I built this with vibe coding! Everyone should try it!" The energy is great, but the AI's "must wrap up" instinct plus the beginner's "AI's got my back" trust is a direct line to failure.&lt;/p&gt;

&lt;p&gt;That's what makes vibe coding dangerous. My working definition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hack on &lt;code&gt;main&lt;/code&gt; in a single session&lt;/li&gt;
&lt;li&gt;Give casual instructions without watching context size&lt;/li&gt;
&lt;li&gt;Believe it "kind of works"&lt;/li&gt;
&lt;li&gt;Wake up with 2,000+ lines of spaghetti&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For toy projects that's fine. But if you keep vibe coding before you hit the "disillusionment phase," it eventually blows up.&lt;/p&gt;
&lt;h4&gt;
  
  
  5. Believing "Implemented!" Without Verification
&lt;/h4&gt;

&lt;p&gt;Separate from context issues: &lt;strong&gt;Even Opus 4.5 with plenty of context often lies about "implemented."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI knows the right facts yet happily outputs code that contradicts them. Knowing something and implementing it correctly are different skills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Countermeasure&lt;/strong&gt;: Have the same AI review its own work.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Me: "Implement this feature."
AI: "Implemented."
Me: "Review it yourself. Are you sure it's spec-compliant?"
AI: "I found the following issues..." (and fixes them immediately)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is why the industry keeps talking about "auto-review by AI." It's an antidote to this exact failure mode. I just didn't know it at the time.&lt;/p&gt;
&lt;h4&gt;
  
  
  6. Giving Vague Specs (I Lacked the Vocabulary)
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Me: "Add an option to ignore case."
AI: "Added --ignore-case."
Result: Values compare case-insensitively, but keys do not.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In my head "ignore case" included keys, but the AI didn't infer that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root issue&lt;/strong&gt;: I lacked the vocabulary to describe development principles.&lt;/p&gt;

&lt;p&gt;When vibe coding breaks down, you need to tell the AI "apply single responsibility" or "separate concerns." If you don't know those phrases, you're stuck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better instructions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ "Add an option to ignore case."
✅ "Add --ignore-case with the following effects:
    1. Compare values case-insensitively.
    2. Compare keys case-insensitively.
    Example: {"Name": "foo"} and {"name": "foo"} should be equal."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Today I'd write at least that much—or have the AI draft such instructions for me. Back then I didn't have the habit.&lt;/p&gt;
&lt;h4&gt;
  
  
  7. Feeding It Outdated Docs
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Me: "Read README.md and implement accordingly."
AI: "Implementation complete based on README."
Result: README was full of lies, so it implemented lies.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Earlier AI sessions had already drifted the docs away from reality.&lt;/p&gt;
&lt;h3&gt;
  
  
  Category C: Quality Assurance Failures
&lt;/h3&gt;
&lt;h4&gt;
  
  
  8. Unreliable Existing Tests
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--workspace&lt;/span&gt;
29 passed&lt;span class="p"&gt;;&lt;/span&gt; 0 failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Seeing green tests felt reassuring. That was a mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it happens&lt;/strong&gt;: Once AI sees the code, it writes tests that pass the current implementation. Of course tests pass on the first run—that's not a win.&lt;/p&gt;

&lt;p&gt;Tools like Serena read the code automatically. You can't hide it. So you must explicitly instruct:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ "Write tests for this code."
✅ "Write tests based on docs/specs/cli.md.
    Do not read the implementation. Tests must derive from the spec."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Why spec-driven development matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In hindsight, that's why "spec-driven development" is trending.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Specs are split into granular issues.&lt;/li&gt;
&lt;li&gt;Each issue includes precise instructions for AI.&lt;/li&gt;
&lt;li&gt;AI picks up the issue and implements it.&lt;/li&gt;
&lt;li&gt;GitHub MCP spins per-feature branches.&lt;/li&gt;
&lt;li&gt;PRs get reviewed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Following that flow automatically prevents vibe-coding disasters. It's just good process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI development maturity pyramid&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's a three-tier pyramid describing AI-assisted development. Vibe coding lives on the bottom tier. Until you reach at least tier two, you can't reliably run public projects. Users will suffer.&lt;/p&gt;


&lt;h2&gt;
  
  
  Chapter 3: The Reboot Process
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Guiding Principle: "Doubt, Verify, Document"
&lt;/h3&gt;

&lt;p&gt;I also used Claude Code for the reboot.&lt;/p&gt;

&lt;p&gt;I confessed everything, asked it for a revival plan, and it delivered something both kind and practical—unlike Kishibe Rohan's confession booth. It worked.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;reboot&lt;/code&gt; subdirectory under &lt;code&gt;.claude&lt;/code&gt; as the command center.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;/init&lt;/code&gt; again to have Serena scan the entire repo from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The process took about three days, so a human had to keep state between sessions. Stretch it longer, and the human becomes the failure point again.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Assume everything outside reboot is untrustworthy.
2. Assume files are half-baked.
3. Assume docs are lying.
4. Figure out which parts are true.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's the human's job. Claude Code is the strategist; I'm the baby Liu Bei just trying to keep up.&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 1: Quarantine
&lt;/h3&gt;

&lt;p&gt;First I moved the existing files into &lt;code&gt;_old/&lt;/code&gt; to create a blank canvas.&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;# Removed or quarantined&lt;/span&gt;
- docs/ &lt;span class="o"&gt;(&lt;/span&gt;including examples&lt;span class="o"&gt;)&lt;/span&gt; → breeding ground &lt;span class="k"&gt;for &lt;/span&gt;unchecked lies
- English and Chinese READMEs
- scripts/ &lt;span class="o"&gt;(&lt;/span&gt;complex CI/CD&lt;span class="o"&gt;)&lt;/span&gt;
- benchmarks &lt;span class="o"&gt;(&lt;/span&gt;non-essential&lt;span class="o"&gt;)&lt;/span&gt;
- CHANGELOG.md, CONTRIBUTING.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: 109 files changed, 32,145 lines deleted.&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 2: Finding the Truth
&lt;/h3&gt;

&lt;p&gt;I took every "it works" statement in README_ja.md and verified it manually.&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;# Test each format&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"a":1}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test1.json
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"a":2}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test2.json
./target/release/diffx test1.json test2.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Findings&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ All six formats (JSON/YAML/TOML/XML/INI/CSV) work.
✅ Output formats (CLI/JSON/YAML) work.
✅ --quiet, --ignore-keys-regex, --epsilon, --array-id-key work.
⚠️  --ignore-case may only affect values, not keys.
❓ --ignore-whitespace and directory diffs unverified.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: The core features worked. The issue was unverified functionality.&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 3: Writing Specs
&lt;/h3&gt;

&lt;p&gt;I documented only the behavior I personally confirmed.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/specs/
├── cli.md   # CLI specs (exit codes, output, options)
└── core.md  # Core API specs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Spec principles&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Describe the ideal behavior before looking at code.&lt;/li&gt;
&lt;li&gt;Check against the implementation.&lt;/li&gt;
&lt;li&gt;Record only what actually works.&lt;/li&gt;
&lt;li&gt;Mark broken parts as TODO.&lt;/li&gt;
&lt;li&gt;Never lie.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Phase 4: Rebuilding Tests
&lt;/h3&gt;

&lt;p&gt;I deleted the 436 existing tests (8,022 lines) and rewrote them based on the specs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New test layout&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/
├── spec/       # Spec-driven unit tests (69 cases)
└── cmd/        # trycmd-based doc-as-test (19 cases)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Why trycmd&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Markdown doubles as documentation and tests.&lt;/li&gt;
&lt;li&gt;Docs can't drift from tests.&lt;/li&gt;
&lt;li&gt;You physically can't write lying docs.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Chapter 4: Leaving the Monorepo
&lt;/h2&gt;
&lt;h3&gt;
  
  
  When to Split
&lt;/h3&gt;

&lt;p&gt;I split when all of these were true:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Different build systems&lt;/strong&gt;: Cargo vs. npm vs. pip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Different release cadences&lt;/strong&gt;: Need independent releases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Different users&lt;/strong&gt;: Rust vs. Node.js vs. Python developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD complexity&lt;/strong&gt;: Cross-language interdependence was unmanageable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;diffx hit all four.&lt;/p&gt;
&lt;h3&gt;
  
  
  How I Split It
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Step 1: Create New Repos
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /home/kako-jun/repos/
&lt;span class="nb"&gt;mkdir &lt;/span&gt;diffx-js &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;diffx-js &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git init
&lt;span class="nb"&gt;mkdir &lt;/span&gt;diffx-python &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;diffx-python &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Step 2: Move Code
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ../diffx/diffx-js/&lt;span class="k"&gt;*&lt;/span&gt; ./diffx-js/
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ../diffx/diffx-python/&lt;span class="k"&gt;*&lt;/span&gt; ./diffx-python/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: I discarded Git history. Keeping it would complicate everything.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 3: Independent Cargo.toml
&lt;/h4&gt;

&lt;p&gt;diffx-js and diffx-python now pull &lt;code&gt;diffx-core&lt;/code&gt; from crates.io.&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;# diffx-js/Cargo.toml&lt;/span&gt;
&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;diffx-core&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.6"&lt;/span&gt;  &lt;span class="c"&gt;# versioned dependency instead of path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Step 4: Remove Them from the Monorepo
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# diffx/Cargo.toml&lt;/span&gt;
&lt;span class="nn"&gt;[workspace]&lt;/span&gt;
&lt;span class="py"&gt;members&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"diffx-core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"diffx-cli"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c"&gt;# diffx-js and diffx-python removed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Structure After the Split
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/kako-jun/repos/
├── diffx/           # Rust only (simple)
│   ├── diffx-core/
│   ├── diffx-cli/
│   └── .github/workflows/
│       ├── ci.yml
│       └── release.yml
│
├── diffx-js/        # npm only
│   └── .github/workflows/
│       ├── ci.yml
│       └── release.yml
│
└── diffx-python/    # pip only
    └── .github/workflows/
        ├── ci.yml
        └── release.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Understandable CI/CD&lt;/strong&gt;: From six workflows + shared repo to two per repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent releases&lt;/strong&gt;: No rush; each language can ship on its own cadence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear ownership&lt;/strong&gt;: Each repo has a single responsibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier contributions&lt;/strong&gt;: Node devs only need to read diffx-js.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Chapter 5: Release Workflow Tips
&lt;/h2&gt;

&lt;p&gt;Splitting the repos taught me one critical principle.&lt;/p&gt;
&lt;h3&gt;
  
  
  Never Combine Build and Publish
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Anti-pattern&lt;/strong&gt;&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="c1"&gt;# ❌ Dangerous workflow&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo build --release&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo publish&lt;/span&gt; &lt;span class="c1"&gt;# publishes before confirming all builds succeed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Why it's bad:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What if Windows/macOS/Linux builds succeed except one?&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cargo publish&lt;/code&gt; cannot be undone.&lt;/li&gt;
&lt;li&gt;Even if you notice, the only fix is to bump the version.&lt;/li&gt;
&lt;li&gt;You burn versions for no reason (v0.6.1 → v0.6.2 → v0.6.3...).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Correct Approach: Two-Stage Release
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ✅ Safe workflow (release.yml)&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-linux&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo build --release&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;

  &lt;span class="na"&gt;build-macos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macos-latest&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="na"&gt;build-windows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="na"&gt;create-release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;build-linux&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;build-macos&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;build-windows&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/download-artifact@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;softprops/action-gh-release@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;diffx-linux/*&lt;/span&gt;
            &lt;span class="s"&gt;diffx-macos/*&lt;/span&gt;
            &lt;span class="s"&gt;diffx-windows/*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ✅ Publish is a separate workflow (publish.yml)&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tag&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;publish"&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release view v${{ inputs.version }}&lt;/span&gt; &lt;span class="c1"&gt;# confirm release exists&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo publish&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Why Two Stages?
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: Push tag → build for all platforms → create GitHub release
        ↓
        Stop here. A human verifies everything.
        ↓
Step 2: Manually trigger the publish workflow
        → Push to crates.io / npm / PyPI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Failure scenarios&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;One-stage workflow&lt;/th&gt;
&lt;th&gt;Two-stage workflow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;macOS build fails&lt;/td&gt;
&lt;td&gt;Broken release already public&lt;/td&gt;
&lt;td&gt;Nothing published&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;Must release v0.6.2, v0.6.3…&lt;/td&gt;
&lt;td&gt;Delete tag, re-push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version consumption&lt;/td&gt;
&lt;td&gt;Wasteful&lt;/td&gt;
&lt;td&gt;Efficient&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Chapter 6: Reboot Playbook
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Correct Reboot Order
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Run the code yourself and find the truth.
2. Write specs in docs/specs/.
3. Build tests from those specs.
4. Fix the implementation until tests pass.
5. Update docs (README, etc.) to match the specs.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Anti-patterns&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing docs first → they turn into lies.&lt;/li&gt;
&lt;li&gt;Trusting existing tests → they only confirm the facade.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What to Delete
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Old tests written without specs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;examples/&lt;/code&gt; directories (they rot into lies).&lt;/li&gt;
&lt;li&gt;Old roadmaps (already executed or obsolete).&lt;/li&gt;
&lt;li&gt;Promo materials (stale after six months).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What to Keep
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docs/specs/&lt;/code&gt; – the single source of truth.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/cmd/&lt;/code&gt; – docs enforced by tests.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.claude/tasks.md&lt;/code&gt; – current task list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; – minimal development rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Time Budget
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Specs: 1 session
Tests: 1 session
Docs: 1 session
Cleanup: 1 session

Total: about four sessions (one session = one context window).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Before (August 2025)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ Frozen for 3 months
❌ Monorepo complexity
❌ Broken CI/CD
❌ Maintaining three languages
❌ Happy as long as "it runs"
❌ Blind faith in existing code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  After (December 2025)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ Back in motion
✅ Lean Rust-only repo
✅ Separate language-specific repos
✅ Focused on Japanese docs
✅ Obsessed with correctness
✅ Doubt everything
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Quantitative Changes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Files&lt;/td&gt;
&lt;td&gt;Many&lt;/td&gt;
&lt;td&gt;-109&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines&lt;/td&gt;
&lt;td&gt;Many&lt;/td&gt;
&lt;td&gt;-27,770&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;436 (meaning?)&lt;/td&gt;
&lt;td&gt;88 (spec-driven)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;README&lt;/td&gt;
&lt;td&gt;3 languages&lt;/td&gt;
&lt;td&gt;3 languages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repositories&lt;/td&gt;
&lt;td&gt;1 (monorepo)&lt;/td&gt;
&lt;td&gt;3 (per language)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Key Lesson
&lt;/h3&gt;

&lt;p&gt;Reviving a project after three months of stagnation didn't require new features or fancy tech.&lt;/p&gt;

&lt;p&gt;It required &lt;strong&gt;the courage to doubt&lt;/strong&gt; and &lt;strong&gt;the courage to delete&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doubt existing tests.&lt;/li&gt;
&lt;li&gt;Doubt the docs.&lt;/li&gt;
&lt;li&gt;Doubt AI status reports.&lt;/li&gt;
&lt;li&gt;Doubt your own sense of "done."&lt;/li&gt;
&lt;li&gt;Delete anything suspicious.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used to wonder why smart people fall for sunk-cost fallacy. Turns out I'm one of them.&lt;/p&gt;

&lt;p&gt;You cling to tests, docs, CI/CD—because "throwing them away" feels wasteful. But keeping broken artifacts helps no one. I finally practiced what I preached and deleted them.&lt;/p&gt;

&lt;p&gt;That's the heart of the reboot and the key to sustainability.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bonus: pre-commit Is Mandatory for AI-Assisted Code
&lt;/h2&gt;

&lt;p&gt;AI introduces a subtle issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS Code's format-on-save never runs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When humans code in VS Code, formatters and &lt;code&gt;.editorconfig&lt;/code&gt; apply automatically. When AI writes files directly, none of that triggers.&lt;/p&gt;

&lt;p&gt;The result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Misaligned indentation&lt;/li&gt;
&lt;li&gt;Missing trailing newlines&lt;/li&gt;
&lt;li&gt;Random import ordering&lt;/li&gt;
&lt;li&gt;Trivial lint warnings everywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CI fails over nonsense and wastes time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution: pre-commit hooks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set up pre-commit so formatting and linting run before every commit. Here's the actual config from diffx-python:&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="c1"&gt;# .pre-commit-config.yaml (diffx-python)&lt;/span&gt;
&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo-fmt&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo fmt&lt;/span&gt;
        &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo fmt --&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system&lt;/span&gt;
        &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;rust&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;pass_filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo-clippy&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo clippy&lt;/span&gt;
        &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo clippy -- -D warnings&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system&lt;/span&gt;
        &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;rust&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;pass_filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/astral-sh/ruff-pre-commit&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0.8.6&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ruff&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--fix&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ruff-format&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/pre-commit/pre-commit-hooks&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v5.0.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trailing-whitespace&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;end-of-file-fixer&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;check-yaml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;check-toml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;check-added-large-files&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;# Setup&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;pre-commit
pre-commit &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In diffx-js (Node.js) I use Husky instead:&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;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(diffx-js)&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;"scripts"&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;"prepare"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"husky"&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;"devDependencies"&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;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^9.1.7"&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;This way, AI-written code gets auto-formatted at commit time.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Repositories&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kako-jun" rel="noopener noreferrer"&gt;
        kako-jun
      &lt;/a&gt; / &lt;a href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;
        diffx
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;diffx&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx/README.ja.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/kako-jun/diffx/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://crates.io/crates/diffx" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/829d21876ad257091fe68d81336d0413406a4e5ff967a43c6169cb29cdd3da4a/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f64696666782e737667" alt="Crates.io"&gt;&lt;/a&gt;
&lt;a href="https://docs.rs/diffx-core" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4564626b8de103a353bbee9f74eee871eaf881ae4a1053c2bdb4dd7cb18663e9/68747470733a2f2f646f63732e72732f64696666782d636f72652f62616467652e737667" alt="docs.rs"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kako-jun/diffx/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Semantic diff tool for structured data (JSON/YAML/TOML/XML/INI/CSV). Ignores key ordering and whitespace, shows only meaningful changes.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why diffx?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Traditional &lt;code&gt;diff&lt;/code&gt; doesn't understand structure:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ diff config_v1.json config_v2.json
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt; {
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;myapp&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;version&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt; }
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; {
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;version&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;myapp&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; }&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;A simple key reordering shows every line as changed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;diffx&lt;/code&gt; shows only semantic changes:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ diffx config_v1.json config_v2.json
&lt;span class="pl-k"&gt;~&lt;/span&gt; version: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; -&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; As CLI tool&lt;/span&gt;
cargo install diffx

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; As library (Cargo.toml)&lt;/span&gt;
[dependencies]
diffx-core = &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;0.6&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Basic&lt;/span&gt;
diffx file1.json file2.json

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Output example&lt;/span&gt;
&lt;span class="pl-k"&gt;~&lt;/span&gt; version: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; -&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
+ features[0]: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;new-feature&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
- deprecated: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;old-value&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Supported Formats&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;JSON, YAML…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;br&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kako-jun" rel="noopener noreferrer"&gt;
        kako-jun
      &lt;/a&gt; / &lt;a href="https://github.com/kako-jun/diffx-js" rel="noopener noreferrer"&gt;
        diffx-js
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;diffx&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx-js/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/kako-jun/diffx-js/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/diffx-js" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cfa758957550c937ae227b921960b06cba433a2be6599ba873ef412abe2253e0/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f64696666782d6a732e737667" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kako-jun/diffx-js/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Node.js bindings for &lt;a href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;diffx&lt;/a&gt; - semantic diff for structured data (JSON, YAML, TOML, XML, INI, CSV). Powered by Rust via napi-rs for blazing fast performance.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install diffx-js&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Supported Platforms&lt;/h3&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;x64 (glibc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;x64 (musl/Alpine)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;ARM64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;x64 (Intel)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;ARM64 (Apple Silicon)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;x64&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Basic Diff&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; diff &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'diffx-js'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;old&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;"Alice"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;age&lt;/span&gt;: &lt;span class="pl-c1"&gt;30&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;newObj&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;"Alice"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;age&lt;/span&gt;: &lt;span class="pl-c1"&gt;31&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;city&lt;/span&gt;: &lt;span class="pl-s"&gt;"Tokyo"&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;results&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;diff&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;old&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;newObj&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;change&lt;/span&gt; &lt;span class="pl-k"&gt;of&lt;/span&gt; &lt;span class="pl-s1"&gt;results&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-smi"&gt;console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;log&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;`&lt;span class="pl-s1"&gt;&lt;span class="pl-kos"&gt;${&lt;/span&gt;&lt;span class="pl-s1"&gt;change&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;diffType&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s1"&gt;&lt;span class="pl-kos"&gt;${&lt;/span&gt;&lt;span class="pl-s1"&gt;change&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;path&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/span&gt;`&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-c"&gt;// Modified: age&lt;/span&gt;
  &lt;span class="pl-c"&gt;// Added: city&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;With Options&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;results&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;diff&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;data1&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;data2&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kako-jun/diffx-js" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;br&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kako-jun" rel="noopener noreferrer"&gt;
        kako-jun
      &lt;/a&gt; / &lt;a href="https://github.com/kako-jun/diffx-python" rel="noopener noreferrer"&gt;
        diffx-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;diffx&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx-python/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/kako-jun/diffx-python/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://pypi.org/project/diffx-python/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ec7ae231f7405aa813ed35e7acc19367cbf2b4d7bf502fbbfd6e14b0e00c2adf/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f64696666782d707974686f6e2e737667" alt="PyPI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kako-jun/diffx-python/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Python bindings for &lt;a href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;diffx&lt;/a&gt; - semantic diff for structured data (JSON, YAML, TOML, XML, INI, CSV). Powered by Rust via PyO3 for blazing fast performance.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install diffx-python&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Supported Platforms&lt;/h3&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;x64 (glibc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;x64 (musl/Alpine)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;ARM64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;x64 (Intel)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;ARM64 (Apple Silicon)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;x64&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Basic Diff&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-python notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;diffx&lt;/span&gt;

&lt;span class="pl-s1"&gt;old&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {&lt;span class="pl-s"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;"Alice"&lt;/span&gt;, &lt;span class="pl-s"&gt;"age"&lt;/span&gt;: &lt;span class="pl-c1"&gt;30&lt;/span&gt;}
&lt;span class="pl-s1"&gt;new&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {&lt;span class="pl-s"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;"Alice"&lt;/span&gt;, &lt;span class="pl-s"&gt;"age"&lt;/span&gt;: &lt;span class="pl-c1"&gt;31&lt;/span&gt;, &lt;span class="pl-s"&gt;"city"&lt;/span&gt;: &lt;span class="pl-s"&gt;"Tokyo"&lt;/span&gt;}

&lt;span class="pl-s1"&gt;results&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;diffx&lt;/span&gt;.&lt;span class="pl-c1"&gt;diff&lt;/span&gt;(&lt;span class="pl-s1"&gt;old&lt;/span&gt;, &lt;span class="pl-s1"&gt;new&lt;/span&gt;)

&lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s1"&gt;change&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-s1"&gt;results&lt;/span&gt;:
    &lt;span class="pl-en"&gt;print&lt;/span&gt;(&lt;span class="pl-s"&gt;f"&lt;span class="pl-s1"&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-s1"&gt;change&lt;/span&gt;[&lt;span class="pl-s"&gt;'type'&lt;/span&gt;]&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s1"&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-s1"&gt;change&lt;/span&gt;[&lt;span class="pl-s"&gt;'path'&lt;/span&gt;]&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/span&gt;"&lt;/span&gt;)
    &lt;span class="pl-c"&gt;# Modified: age&lt;/span&gt;
    &lt;span class="pl-c"&gt;# Added: city&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;With Options&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-python notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;results&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;diffx&lt;/span&gt;.&lt;span class="pl-c1"&gt;diff&lt;/span&gt;(&lt;span class="pl-s1"&gt;data1&lt;/span&gt;, &lt;span class="pl-s1"&gt;data2&lt;/span&gt;
    &lt;span class="pl-s1"&gt;epsilon&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;0.001&lt;/span&gt;,                      &lt;span class="pl-c"&gt;# Tolerance for float comparison&lt;/span&gt;
    &lt;span class="pl-s1"&gt;array_id_key&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;'id'&lt;/span&gt;,                  &lt;span class="pl-c"&gt;# Match array elements&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kako-jun/diffx-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;I haven't written formal release posts yet, but the initial versions of these projects work, and that's enough to prove the reboot process is repeatable—at least for my ecosystem.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kako-jun" rel="noopener noreferrer"&gt;
        kako-jun
      &lt;/a&gt; / &lt;a href="https://github.com/kako-jun/diffai" rel="noopener noreferrer"&gt;
        diffai
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;diffai&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffai/README.ja.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffai/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/kako-jun/diffai/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://crates.io/crates/diffai" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cbc28fd50c67535a41e318fdd2807d340a24db904221702a778e995a384eecff/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f6469666661692e737667" alt="Crates.io"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kako-jun/diffai/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Semantic diff tool for AI/ML models (PyTorch, Safetensors, NumPy, MATLAB). Provides tensor statistics, parameter comparisons, and automatic ML analysis.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why diffai?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Traditional &lt;code&gt;diff&lt;/code&gt; doesn't understand binary ML files:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ diff model_v1.pt model_v2.pt
Binary files model_v1.pt and model_v2.pt differ&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;diffai&lt;/code&gt; shows meaningful analysis:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ diffai model_v1.safetensors model_v2.safetensors
learning_rate_analysis: old=0.001, new=0.0015, change=+50.0%
gradient_analysis: flow_health=healthy, norm=0.021
&lt;span class="pl-k"&gt;~&lt;/span&gt; fc1.weight: mean=-0.0002-&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;-0.0001, std=0.0514-&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;0.0716
&lt;span class="pl-k"&gt;~&lt;/span&gt; fc2.weight: mean=-0.0008-&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;-0.0018, std=0.0719-&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;0.0883&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; As CLI tool&lt;/span&gt;
cargo install diffai

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; As library (Cargo.toml)&lt;/span&gt;
[dependencies]
diffai-core = &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;0.5&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Basic&lt;/span&gt;
diffai model1.pt model2.pt

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; JSON output for automation&lt;/span&gt;
diffai model1.safetensors model2.safetensors --output json

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; With numerical tolerance&lt;/span&gt;
diffai weights1.npy weights2.npy --epsilon 0.001&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Supported Formats&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PyTorch&lt;/strong&gt; (.pt, .pth) - Full ML analysis + tensor statistics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safetensors&lt;/strong&gt; (.safetensors) - Full ML analysis + tensor statistics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NumPy&lt;/strong&gt; (.npy, .npz) - Tensor statistics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MATLAB&lt;/strong&gt; (.mat) - Tensor statistics&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Main Options&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;--format &lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kako-jun/diffai" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kako-jun" rel="noopener noreferrer"&gt;
        kako-jun
      &lt;/a&gt; / &lt;a href="https://github.com/kako-jun/lawkit" rel="noopener noreferrer"&gt;
        lawkit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;lawkit&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/lawkit/README.ja.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/kako-jun/lawkit/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/kako-jun/lawkit/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://crates.io/crates/lawkit" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6d7057ee95182a749590a2629b94ef3721b0a7fe01f8f739684fb00ede84c3f3/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f6c61776b69742e737667" alt="Crates.io"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kako-jun/lawkit/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Statistical law analysis toolkit. Analyze data for Benford's law, Pareto principle, Zipf's law, Normal and Poisson distributions. Detect anomalies and assess data quality.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;cargo install lawkit&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Supported Laws&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Benford's Law (Fraud Detection)&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ lawkit benf financial_data.csv
Benford Law Analysis Results

Dataset: financial_data.csv
Numbers analyzed: 1000
[LOW] Dataset analysis

First Digit Distribution:
1: ███████████████┃░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  30.1% (expected:  30.1%)
2: █████████┃░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  17.6% (expected:  17.6%)
3: ██████┃░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  12.5% (expected:  12.5%)
...&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Pareto Principle (80/20 Rule)&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ lawkit pareto sales.csv
Pareto Principle (80/20 Rule) Analysis Results

Dataset: sales.csv
Numbers analyzed: 500
[LOW] Dataset analysis

Lorenz Curve (Cumulative Distribution):
 20%: ███████████████████████████████████████┃░░░░░░░░░░  79.2% cumulative (80/20 point)
 40%: █████████████████████████████████████████████░░░░░  91.5% cumulative
...

80/20 Rule: Top 20% owns 79.2% of total wealth (Ideal: 80.0%, Ratio: 0.99)&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Zipf's Law (Frequency Distribution)&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ lawkit zipf word_frequencies.csv
Zipf Law Analysis Results
Dataset: word_frequencies.csv
Numbers analyzed: 1000
[LOW] Dataset analysis

Rank-Frequency Distribution:
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 1: █████████████████████████████████████████████████┃  11.50% (expected: 11.50%)&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 2:&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kako-jun/lawkit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




</description>
      <category>rust</category>
      <category>opensource</category>
      <category>ai</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Introducing Diffx: A Rust-Based AI Diff Tool That Understands Structure</title>
      <dc:creator>kako-jun</dc:creator>
      <pubDate>Sun, 06 Jul 2025 05:09:56 +0000</pubDate>
      <link>https://forem.com/kako-jun/i-built-diffx-a-structure-aware-ai-first-diff-tool-in-rust-lets-end-the-comma-induced-suffering-491h</link>
      <guid>https://forem.com/kako-jun/i-built-diffx-a-structure-aware-ai-first-diff-tool-in-rust-lets-end-the-comma-induced-suffering-491h</guid>
      <description>&lt;p&gt;Ever struggled with meaningless diffs caused by commas or formatting?&lt;br&gt;&lt;br&gt;
I did too — so I built Diffx, a Rust-based AI tool that understands structure.&lt;br&gt;&lt;br&gt;
Here's how it works and why it might change how you compare 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%2Frhskfjafrn19c8t25m7q.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%2Frhskfjafrn19c8t25m7q.png" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ever felt that twinge of frustration when you &lt;code&gt;git diff&lt;/code&gt; a config file like &lt;code&gt;JSON&lt;/code&gt; or &lt;code&gt;YAML&lt;/code&gt;?&lt;br&gt;
You know, when a simple key reordering floods your screen with a sea of "changes."&lt;br&gt;
Or that one-character indent change! That trailing comma!&lt;/p&gt;

&lt;p&gt;Traditional &lt;code&gt;diff&lt;/code&gt; tools compare text line by line, which means they have no clue about the &lt;em&gt;structure&lt;/em&gt; of your data.&lt;br&gt;
It's a small stress, sure. But it adds up, day after day.&lt;/p&gt;

&lt;p&gt;"I need a smarter &lt;code&gt;diff&lt;/code&gt; tool, one that gets the structure!"&lt;br&gt;
...and by the time I thought that, I had already built it. Rage-driven development!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;https://github.com/kako-jun/diffx&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What is &lt;code&gt;diffx&lt;/code&gt;?: A Diff Tool for Structured Data
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;diffx&lt;/code&gt; is a CLI tool built in Rust, specializing in structured data formats like &lt;code&gt;JSON&lt;/code&gt;, &lt;code&gt;YAML&lt;/code&gt;, &lt;code&gt;TOML&lt;/code&gt;, &lt;code&gt;XML&lt;/code&gt;, &lt;code&gt;INI&lt;/code&gt;, and &lt;code&gt;CSV&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its killer feature is understanding the structural meaning of your data and displaying differences accordingly.&lt;br&gt;
For example, let's look at a common config file change.&lt;/p&gt;

&lt;p&gt;Before: &lt;code&gt;config_v1.json&lt;/code&gt;&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"server"&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;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8080&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;"features"&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;"auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"logging"&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;After: &lt;code&gt;config_v2.json&lt;/code&gt;&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"server"&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;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost"&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;"features"&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;"auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"logging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cache"&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;If you view this with &lt;code&gt;git diff&lt;/code&gt;, it's a mess of changes that makes it hard to see what's going on. Your eyes just glaze over.&lt;/p&gt;

&lt;p&gt;But with &lt;code&gt;diffx&lt;/code&gt;, the output looks like this:&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="nv"&gt;$ &lt;/span&gt;diffx config_v1.json config_v2.json
~ version: &lt;span class="s2"&gt;"1.0.0"&lt;/span&gt; -&amp;gt; &lt;span class="s2"&gt;"1.0.1"&lt;/span&gt;
~ server.port: 8080 -&amp;gt; 8081
+ server.host: &lt;span class="s2"&gt;"localhost"&lt;/span&gt;
+ features[2]: &lt;span class="s2"&gt;"cache"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;~&lt;/code&gt; means a value changed, and &lt;code&gt;+&lt;/code&gt; means something was added.&lt;br&gt;
It also uses universal design colors, so it's intuitive even for those with color vision deficiency!&lt;/p&gt;

&lt;p&gt;This way, you can intuitively understand "which key changed and how?" or "what was added to which array?" in a clear path format.&lt;br&gt;
I'm calling it the &lt;code&gt;diffx&lt;/code&gt; format! Right now!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Formats&lt;/th&gt;
&lt;th&gt;Semantic Aware&lt;/th&gt;
&lt;th&gt;Array Tracking&lt;/th&gt;
&lt;th&gt;Config Support&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;diffx&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Semantic&lt;/td&gt;
&lt;td&gt;JSON/YAML/TOML/XML/INI/CSV&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Structured data comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;diff&lt;/td&gt;
&lt;td&gt;Text-based&lt;/td&gt;
&lt;td&gt;Any text&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;General text files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jq&lt;/td&gt;
&lt;td&gt;JSON processor&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;JSON manipulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yq&lt;/td&gt;
&lt;td&gt;YAML processor&lt;/td&gt;
&lt;td&gt;YAML/JSON&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;YAML manipulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;daff&lt;/td&gt;
&lt;td&gt;Tabular&lt;/td&gt;
&lt;td&gt;CSV&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;CSV/spreadsheet data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jsondiff&lt;/td&gt;
&lt;td&gt;JSON diff&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;JSON-only comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deep-diff&lt;/td&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;JSON/Objects&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;JavaScript applications&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  A Design for the Future?
&lt;/h2&gt;

&lt;p&gt;I poured endless possibilities into this so it wouldn't just be another diff tool.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. &lt;code&gt;AI&lt;/code&gt;-First Design
&lt;/h3&gt;

&lt;p&gt;The output format of &lt;code&gt;diffx&lt;/code&gt; is designed not only to be human-readable but also easy for &lt;code&gt;AI&lt;/code&gt; to parse.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;AI&lt;/code&gt; agent using &lt;code&gt;diffx&lt;/code&gt; could handle instructions like, "Summarize the key points of this configuration change."&lt;br&gt;
My goal is a future where &lt;code&gt;AI&lt;/code&gt; agents ask humans, "Could you please install &lt;code&gt;diffx&lt;/code&gt; for me?"&lt;/p&gt;

&lt;p&gt;Even more interesting is the meta-concept of "self-chaining," where you can output the &lt;code&gt;diffx&lt;/code&gt; result in &lt;code&gt;JSON&lt;/code&gt; or &lt;code&gt;YAML&lt;/code&gt; format and then diff &lt;em&gt;that&lt;/em&gt; output with &lt;code&gt;diffx&lt;/code&gt; again.&lt;br&gt;
This allows you to get a "diff of diffs," which opens up huge possibilities for tracking the history of configuration changes or managing multiple prototypes of config files.&lt;br&gt;
I hope this sparks-joy-and-ideas for you.&lt;/p&gt;

&lt;p&gt;I've also built another &lt;code&gt;Rust&lt;/code&gt; CLI called &lt;code&gt;lawkit&lt;/code&gt;, which outputs in YAML. &lt;code&gt;diffx&lt;/code&gt; has already proven itself useful there, creating powerful chains in my shell scripts.&lt;br&gt;
&lt;a href="https://github.com/kako-jun/lawkit" rel="noopener noreferrer"&gt;https://github.com/kako-jun/lawkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lawkit&lt;/code&gt; is a tool that uses natural laws like Benford's Law to detect falsification in accounting documents and experimental evidence.&lt;/p&gt;

&lt;p&gt;And though it's not released yet, I'm also working on &lt;code&gt;diffai&lt;/code&gt;, a &lt;code&gt;Rust&lt;/code&gt; CLI for comparing &lt;code&gt;AI&lt;/code&gt;-related static files (think tensor shape comparisons, weight statistics...).&lt;br&gt;
&lt;a href="https://github.com/kako-jun/diffai" rel="noopener noreferrer"&gt;https://github.com/kako-jun/diffai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Its output will also be in &lt;code&gt;YAML&lt;/code&gt; format, adding even more fuel to the chaining fire.&lt;br&gt;
It's like a never-ending combo chain from a video game!&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Simple, Unified Diff Format
&lt;/h3&gt;

&lt;p&gt;No matter what formats you're comparing, the output is always the unified &lt;code&gt;diffx&lt;/code&gt; format.&lt;br&gt;
It's simple, so the learning curve should be low.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Handy Options for Programming
&lt;/h3&gt;

&lt;p&gt;I've implemented every useful feature I could think of for daily programming, so it should stand up to some pretty niche use cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--ignore-keys-regex&lt;/code&gt;: Exclude keys you want to ignore, like timestamps, using regular expressions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;diffx ./dir1 ./dir2&lt;/code&gt;: Recursively compare two directories.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--array-id-key&lt;/code&gt;: Identify objects within an array by a key like &lt;code&gt;id&lt;/code&gt; to accurately track changes.&lt;/li&gt;
&lt;li&gt;There's also a high-speed mode for comparing huge files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It might even happen to meet the professional needs of a corporate environment.&lt;br&gt;
If not, please file an issue on &lt;code&gt;GitHub&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Making it More Accessible
&lt;/h2&gt;

&lt;p&gt;I wanted as many people as possible to use it, so it's built in &lt;code&gt;Rust&lt;/code&gt; (cross-platform).&lt;br&gt;
You can easily install it with &lt;code&gt;cargo&lt;/code&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="nv"&gt;$ &lt;/span&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;diffx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executables for each OS are also available for download from &lt;code&gt;GitHub Releases&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://github.com/kako-jun/diffx/releases" rel="noopener noreferrer"&gt;https://github.com/kako-jun/diffx/releases&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, I've created wrapper packages for &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; so you can use it in your &lt;code&gt;Python&lt;/code&gt; and &lt;code&gt;Node.js&lt;/code&gt; projects.&lt;br&gt;
&lt;a href="https://pypi.org/project/diffx-python/" rel="noopener noreferrer"&gt;https://pypi.org/project/diffx-python/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/diffx-js" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/diffx-js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can summon the power of &lt;code&gt;diffx&lt;/code&gt; (which is super fast) seamlessly from these languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smothering You With Documentation!
&lt;/h2&gt;

&lt;p&gt;Even though it's a personal project, I went all-in on the documentation from the start.&lt;br&gt;
Installation instructions, a comprehensive explanation of all options, and a wealth of examples for various use cases. I've included everything I could think of, so it should be safe enough for a grade-schooler to use!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentation: &lt;a href="https://github.com/kako-jun/diffx/blob/main/docs/index.md" rel="noopener noreferrer"&gt;https://github.com/kako-jun/diffx/blob/main/docs/index.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used &lt;code&gt;Claude Code&lt;/code&gt;'s &lt;code&gt;Pro&lt;/code&gt; plan for development and translation.&lt;br&gt;
Even someone like me, whose Japanese is imperfect, could build this!&lt;br&gt;
I thought it was $20/month and regenerated the code over and over, only to get a bill for $20 + $220. I was shocked. So, the more you read this, the more I recoup my investment!&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;diffx&lt;/code&gt; is a very simple tool. If you've ever had the same frustrations with diffing, please give it a try.&lt;/p&gt;

&lt;p&gt;I'm gradually realizing just how convenient this tool is and the potential it holds.&lt;br&gt;
I'm not sure how seasoned developers will feel, but I'd be thrilled if it turns out to be a hidden gem that makes you think, "This is exactly what I've been looking for!"&lt;/p&gt;

&lt;p&gt;My cat was on my lap the entire time I was developing this.&lt;br&gt;
If you could star it on &lt;code&gt;GitHub&lt;/code&gt;, you'll probably startle my cat (because I'll be doing a victory pump).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kako-jun/diffx" rel="noopener noreferrer"&gt;https://github.com/kako-jun/diffx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback, bug reports, and feature requests are all welcome.&lt;br&gt;
Thank you for reading to the end.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
