<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Open-Source | AkitaOnRails.com</title><link>https://akitaonrails.github.io/en/tags/open-source/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 19 Oct 2026 23:20:52 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/en/tags/open-source/index.xml" rel="self" type="application/rss+xml"/><item><title>I Self-Published My Own Book/e-book: Competent Enough</title><link>https://akitaonrails.github.io/en/2026/10/13/i-self-published-my-own-book-ebook-competent-enough/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/10/13/i-self-published-my-own-book-ebook-competent-enough/</guid><pubDate>Tue, 13 Oct 2026 19:00:00 -0300</pubDate><description>&lt;p&gt;I just published my own book about artificial intelligence. It&amp;rsquo;s called &lt;em&gt;Competent Enough&lt;/em&gt;, subtitled &amp;ldquo;A year putting artificial intelligence to the test, without fear and without propaganda&amp;rdquo;, and it&amp;rsquo;s free, in EPUB and PDF, to read on your phone, PC or Kindle. The official page is &lt;a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener"&gt;here&lt;/a&gt;, and the &lt;a href="https://github.com/akitaonrails/ai-book-2026"target="_blank" rel="noopener"&gt;repository&lt;/a&gt; is public.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener"&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261013190000_book-competent-enough-3d.png" alt="Competent Enough, the book, in 3D" loading="lazy" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The book consolidates almost everything I wrote about AI on this blog from February to October 2026: all the experiments, the Frank projects, the benchmarks, billions of tokens spent and hundreds of hours of work over eight months, reorganized into a format that&amp;rsquo;s easier to read than a pile of dated posts. It came out in Portuguese and in English.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I just published my own book about artificial intelligence. It&rsquo;s called <em>Competent Enough</em>, subtitled &ldquo;A year putting artificial intelligence to the test, without fear and without propaganda&rdquo;, and it&rsquo;s free, in EPUB and PDF, to read on your phone, PC or Kindle. The official page is <a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener">here</a>, and the <a href="https://github.com/akitaonrails/ai-book-2026"target="_blank" rel="noopener">repository</a> is public.</p>
<p><a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261013190000_book-competent-enough-3d.png" alt="Competent Enough, the book, in 3D"  loading="lazy" /></a></p>
<p>The book consolidates almost everything I wrote about AI on this blog from February to October 2026: all the experiments, the Frank projects, the benchmarks, billions of tokens spent and hundreds of hours of work over eight months, reorganized into a format that&rsquo;s easier to read than a pile of dated posts. It came out in Portuguese and in English.</p>
<blockquote>
  <p><strong>Important notice:</strong> this is a <em>preview</em>. The book is still in progress and new versions will come out until I consider it done. If you find anything wrong, from a typo to a fact, <a href="https://github.com/akitaonrails/ai-book-2026/issues"target="_blank" rel="noopener">open an issue on GitHub</a>. The trail I describe below exists precisely so that the fix reaches the right paragraph.</p>

</blockquote>
<p>This text is about the technical backstage. How you turn 131 blog posts, written over months, with opinions that changed along the way, into a book with a beginning, middle, end, appendices, glossary and bibliography. And how you do that with agents without losing control of what the book says.</p>
<h2>What&rsquo;s inside<span class="hx:absolute hx:-mt-20" id="whats-inside"></span>
    <a href="#whats-inside" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Five parts, each answering a question people keep asking me:</p>
<ol>
<li><strong>What is this thing, anyway.</strong> Is it intelligent? Is AGI coming?</li>
<li><strong>The marathon.</strong> Does it actually work, or is it all demo?</li>
<li><strong>Numbers and propaganda.</strong> Which AI is best? Can you believe the announcements?</li>
<li><strong>Who keeps the keys.</strong> Is it dangerous to let it touch my things?</li>
<li><strong>And my job?</strong> Will it replace me? What comes next?</li>
</ol>
<p>That&rsquo;s 20 chapters and two interludes, plus a preface, a &ldquo;how to read&rdquo;, a &ldquo;before you start&rdquo; saying what the book doesn&rsquo;t explain and where to learn it, an epilogue and an afterword. Then come ten appendices (the machine inside without math, further reading, how to study with AI at your side, three bubbles, a timeline, a minimal kit for using agents safely, ai-memory, how to read a benchmark or an announcement, the year&rsquo;s projects, and the backstage for programmers), the sources, the image credits, a glossary of almost 150 terms and more than 300 references in ABNT style. The print edition passes 500 pages at 6 by 9 inches; the screen edition, around 475. There are more than 50 figures, all with a provenance record.</p>
<p>The audience is different from the blog&rsquo;s. The book was written for people who are anxious or confused about AI: the professional afraid of being replaced, the parent who read that AGI is two years away, the manager being sold an &ldquo;AI transformation&rdquo;. Most of them don&rsquo;t program. That changes the voice, and I&rsquo;ll come back to it.</p>
<h2>The problem: half a million words that disagree with each other<span class="hx:absolute hx:-mt-20" id="the-problem-half-a-million-words-that-disagree-with-each-other"></span>
    <a href="#the-problem-half-a-million-words-that-disagree-with-each-other" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On October 12 I published <a href="/en/2026/10/12/llms-agents-competent-enough/">the year&rsquo;s synthesis</a>, which became chapter 20. On the 13th I started the book. I had 131 posts from 2026 on the blog, almost half a million words, from model benchmarks to a bitcoin wallet.</p>
<p>Reorganizing that by hand would take months. And there&rsquo;s a worse problem than volume: I changed my mind during the year. I redid the benchmark several times, corrected costs, switched tools, and a February post contradicts a September one with complete naturalness. A book that simply pasted the posts in order would be a book that contradicts itself.</p>
<p>So I did what the whole book describes: I handed the grunt work to coding agents and kept the part of deciding, building the process and checking. The process is the subject of this text.</p>
<h2>Step 1: a sealed inventory<span class="hx:absolute hx:-mt-20" id="step-1-a-sealed-inventory"></span>
    <a href="#step-1-a-sealed-inventory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The first thing was a script that reads the 131 posts and records, for each one, the SHA-256 hash of the Portuguese file and of the English file, plus the exact commit of the blog repository everything was read from. If a comma changes in a post, the hash changes with it. That file is machine-generated and never edited by hand.</p>
<p>Then an agent read each post and filled out a fixed form, with a schema defined in YAML: the thesis in one or two sentences, the claims a book would need to verify, which of them age fast, which lay reader&rsquo;s fear the text answers, what to cut. Each analysis carries the hash of the post it came from.</p>
<p>Of the 131 texts, 96 had AI as the central subject or with relevant weight. The others only came in when they taught something specific, and every AI post left out has its reason recorded in the structure file. A script fails the structure if any AI post is left without a destination.</p>
<h3>Lineage: who supersedes whom<span class="hx:absolute hx:-mt-20" id="lineage-who-supersedes-whom"></span>
    <a href="#lineage-who-supersedes-whom" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>To solve the contradiction problem, there&rsquo;s a lineage map. It says which post superseded which, what can still be salvaged from the older one, and which corrections coming from the reference projects (the benchmark repository, ai-memory&rsquo;s, ai-jail&rsquo;s, my home server notes) apply to each text.</p>
<p>The rule for chapters is to tell the most recent state and, when the change teaches something, tell the change. &ldquo;In June I thought X; in July the numbers said Y&rdquo; is a story. Printing the old number as if it were current is an error, and the checker treats it as an error.</p>
<h2>Step 2: the structure is data, and it generates the configuration<span class="hx:absolute hx:-mt-20" id="step-2-the-structure-is-data-and-it-generates-the-configuration"></span>
    <a href="#step-2-the-structure-is-data-and-it-generates-the-configuration" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>From the analyses came a proposed structure: five parts, each answering a reader&rsquo;s fear, twenty chapters, two interludes. I read it, changed it and approved it. Some pieces came in at my request, like the &ldquo;before you start&rdquo; and the appendix on the machine inside.</p>
<p>That structure lives in a single YAML file, and it&rsquo;s the source of truth. Each chapter has its id, title, opening scene, the question it answers, the arc, the list of source posts and the figure ideas. The Quarto configuration, which assembles the book, is generated from that file by script. Nobody edits the configuration by hand.</p>
<p>This matters because structural change is where a book breaks. Midway I moved the cut-off: the January posts went out, and the story settled between February and October. Ten posts vanished from the base.</p>
<p>Three chapters needed a new scene, a dozen units needed small repairs, and the damage that&rsquo;s hard to see was elsewhere: a sentence in an untouched chapter saying &ldquo;the five reviewers from chapter 5&rdquo;, the timeline, the projects appendix, chart labels, every translation. That&rsquo;s why there&rsquo;s an impact script that, before any edit, lists every paragraph, figure, reference and translation that depends on a post.</p>
<h2>Step 3: a pilot chapter becomes a contract<span class="hx:absolute hx:-mt-20" id="step-3-a-pilot-chapter-becomes-a-contract"></span>
    <a href="#step-3-a-pilot-chapter-becomes-a-contract" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before scaling, a pilot chapter. I picked chapter 5, about the first ten percent of a project, and it served to calibrate the voice and discover the doubts an agent would have along the way. Each doubt resolved became a written rule.</p>
<p>Those rules went into a contract document every agent reads before writing, along with three things:</p>
<ul>
<li>the book&rsquo;s voice guide, which inherits the blog&rsquo;s rules (my WRITER.md, the humanizer and my finishing checklist) and only adds what changes when the text leaves a dated post and goes into a book a lay reader holds in their hands;</li>
<li>a continuity file, saying which chapter explains each concept and what each character is called, so nobody explains &ldquo;context window&rdquo; five times;</li>
<li>the entire structure, so each agent knows what the other chapters cover.</li>
</ul>
<p>Besides the voice rules that already existed (a chapter opens on a scene with a date, a place and something at stake, never on a definition; it closes on a hook toward the next one, never on &ldquo;in this chapter we saw&rdquo;), some of the rules that came out of the pilot, to give you a taste:</p>
<ul>
<li>when the chapter brief and the post disagree on a detail, the post wins;</li>
<li>the chapter that owns a concept explains it properly; if the term shows up earlier in reading order, it gets a half-sentence gloss and a pointer, never a second explanation;</li>
<li>a fact verified online gets a citation even if the original post had no link;</li>
<li>model and product names in the vendor&rsquo;s spelling, even when the blog abbreviated them.</li>
</ul>
<blockquote>
  <p>It&rsquo;s the project instructions file I describe in the chapter about how to talk to the machine, at the scale of a book. Anyone who has written an AGENTS.md for a codebase recognizes all of it.</p>

</blockquote>
<h2>Step 4: parallel drafts, contradictions expected<span class="hx:absolute hx:-mt-20" id="step-4-parallel-drafts-contradictions-expected"></span>
    <a href="#step-4-parallel-drafts-contradictions-expected" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>With the contract ready, the chapters were drafted in parallel, one agent per chapter, in two waves: parts I and II first, then III through V, so the later chapters could build on the earlier ones. Each agent received its chapter&rsquo;s brief, the analyses, the full posts, the lineage and the reference-project files it needed.</p>
<p>Agents working at the same time contradict each other, and that happened. One chapter said FrankMD had around 130 commits in three days; another, that it had 212 in 19 days. Both numbers came from the posts and were right, they were just different windows. An integration ledger collected those conflicts, and the rule became making the window explicit in each chapter.</p>
<p>After the drafts comes the integration pass, with another set of agents, each owning a group of chapters and forbidden from touching the others. Their job: apply the conflict ledger, cut concepts explained twice, check that every callback matches what the other chapter actually says, make sure the last paragraph of a chapter leads into the first of the next, and redo the fact-check assuming the draft is wrong.</p>
<p>To read the seams, the build generates a &ldquo;seams&rdquo; file: the final paragraph of each unit next to the opening paragraph of the next. It&rsquo;s the fastest read there is for finding where the book stops feeling like one book.</p>
<h2>Step 5: an invisible marker per paragraph<span class="hx:absolute hx:-mt-20" id="step-5-an-invisible-marker-per-paragraph"></span>
    <a href="#step-5-an-invisible-marker-per-paragraph" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the part I find most useful in the whole project. Every paragraph of the book, in the source file, carries a comment saying where it came from:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">&lt;!-- src: 2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas --&gt;
</span></span><span class="line"><span class="cl">Every LLM was trained only on what is public...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;!-- src: original --&gt;
</span></span><span class="line"><span class="cl">New text, written for the book.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;!-- src: ref:ai-jail/README.md --&gt;
</span></span><span class="line"><span class="cl">Fact checked in the reference project.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The marker disappears when the book is built, through a Pandoc Lua filter, so the reader never sees it. It exists for maintenance. I edit posts after publishing all the time, and the book has to follow.</p>
<p>The <code>rake drift</code> command redoes the inventory, compares the hashes, and lists the chapters that depend on a post that changed, with the post&rsquo;s diff since the commit at which the book last read it. The marker leads straight to the paragraphs that came from that post, and only those need review. Once resolved, a script records the new hash and the commit.</p>
<p>A real example, from today. I removed from the <a href="/en/2026/10/13/ai-reverse-engineering-is-adobe-dead/">reverse engineering post</a> a paragraph about a Linus Tech Tips video. <code>drift</code> flagged chapter 19 and one appendix; the diff showed that passage had never been used in the book; two commands later, both were stamped with the new hash. Without the marker, I&rsquo;d have had to reread two chapters to discover I didn&rsquo;t need to change anything.</p>
<p>The bibliography plays the same role for external sources: each reference records which post cited it. And each image has its own provenance record.</p>
<h2>Step 6: what the fact-check caught<span class="hx:absolute hx:-mt-20" id="step-6-what-the-fact-check-caught"></span>
    <a href="#step-6-what-the-fact-check-caught" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every number, date and name was checked against three oracles: the posts, the reference projects and primary sources online, with the same adversarial checker prompt I use on the blog&rsquo;s articles. The full list is in the book&rsquo;s afterword, and a good part of the corrections are to my own blog:</p>
<ul>
<li>in the March review of the Strix Halo mini-PC, I had set aside 96 GB of memory for the GPU; in April I lowered it to 64, and later posts still said 96. The book uses 64 for everything after April;</li>
<li>a counting bug in one of the benchmark&rsquo;s tools undercounted by 40 to 90 times the cost of runs made on it before August. The book cites none of those costs;</li>
<li>in the June text about Claude Fable 5, I wrote it cost ten times more than Opus 4.8 per run. Redoing the math in July, with cache-read tokens included, Fable cost almost double. The post still says ten times; the book tells the wrong number and the correction;</li>
<li>in a March text, I wrote that Anthropic had bought Bun at the end of 2024. The announcement is from December 2025;</li>
<li>a chapter summary, written by an agent, said Claude Code&rsquo;s subscription lock fell in less than a day after the leak. The announcement came about 30 hours later, and the book says &ldquo;the next day&rdquo;.</li>
</ul>
<blockquote>
  <p>The drafts came out fast. Confidence in the text came from the checking. And the source beats the summary, even when the summary comes from the machine.</p>

</blockquote>
<h2>Step 7: a chapter with an error doesn&rsquo;t pass<span class="hx:absolute hx:-mt-20" id="step-7-a-chapter-with-an-error-doesnt-pass"></span>
    <a href="#step-7-a-chapter-with-an-error-doesnt-pass" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On top of everything runs an automatic checker, the equivalent of continuous integration. They&rsquo;re Ruby scripts, standard library only, chained in a Rakefile, plus what they call externally: the chart checker is Python because it lives inside matplotlib, the page audit uses poppler, and epubcheck needs Java:</p>
<ul>
<li>a <strong>chapter linter</strong> fails em dashes, phrases banned by the voice guide, loose URLs in the middle of prose, unknown citation keys, paragraphs without a provenance marker, and warns about overlong paragraphs;</li>
<li>a <strong>doctor</strong> checks that every cross-reference, citation, glossary term and figure exists, that provenance matches the inventory, that no post before the cut-off leaked in, that translations are up to date, and runs a callback heuristic: a sentence pointing at another chapter using names that chapter no longer contains;</li>
<li>a <strong>page audit</strong> opens the finished PDF and looks for blocks split across pages, headings orphaned at the foot of a page, nearly empty pages, oversized images, lines overflowing the margin;</li>
<li>a <strong>chart checker</strong> looks for labels that spilled out of their boxes;</li>
<li><strong>epubcheck</strong> validates the EPUB 3;</li>
<li>a <strong>style report</strong> for copyediting: passages repeated across chapters (an inevitable consequence of posts that repeat the same thesis from different angles), recurring phrases, overused words, term variants, badly formed comparatives in Portuguese.</li>
</ul>
<p>And the scripts have tests. A suite of almost 170 tests builds a fake book in a temporary directory, with five fake posts in a fake git repository, and checks that each tool catches the problem it should catch. When a bug is fixed, the test that would have caught it goes in, with a comment naming the regression it guards. It runs in CI before every build.</p>
<h2>The assembly pipeline<span class="hx:absolute hx:-mt-20" id="the-assembly-pipeline"></span>
    <a href="#the-assembly-pipeline" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The toolchain is Quarto, which bundles Pandoc and Typst, version-pinned inside the repository. No LaTeX. A single <code>rake build</code> produces, from the same tree of Markdown files:</p>
<table>
  <thead>
      <tr>
          <th>Output</th>
          <th>For what</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>EPUB 3</td>
          <td>Kindle, Kobo, Apple Books, any reader</td>
      </tr>
      <tr>
          <td>Screen PDF</td>
          <td>reading on a computer or tablet, with the cover</td>
      </tr>
      <tr>
          <td>Print PDF</td>
          <td>6 by 9 inches, blank versos, chapters opening on the right</td>
      </tr>
      <tr>
          <td>HTML</td>
          <td>web edition</td>
      </tr>
      <tr>
          <td>DOCX</td>
          <td>for an editor who wants Word</td>
      </tr>
  </tbody>
</table>
<p>Portuguese and English are Quarto profiles, generated from the same structure file. Citations come from a YAML in CSL format shared by both editions, with an ABNT style adjusted for Portuguese. The glossary is a Lua filter: each term is marked in the source where it appears, and the filter links the mark to the entry, expands the acronym the first time and generates the page.</p>
<p>Typst solved something I thought would cost me weeks: a PDF that looks like a typeset book, Portuguese hyphenation, ligatures, without the pain of TeX. The page audit after the build catches what the engine let through, and a <code>rake fit</code> recompiles while tightening chapters that end on a nearly empty page.</p>
<h3>The figures<span class="hx:absolute hx:-mt-20" id="the-figures"></span>
    <a href="#the-figures" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every figure is code or has a record. Charts and box-and-arrow diagrams are matplotlib scripts, 43 of them, each with a note of the chapter the data came from, and with the labels in Portuguese and English inside the script itself: the same chart comes out in both languages. The path for D2 diagrams exists in the repository, and no figure in the book needed it.</p>
<p>The conceptual illustrations were generated by AI, with the model, the prompt and the date of each one recorded in its credit record, and the book discloses it. The rule I imposed on myself: no AI-generated image of a real person. Real people only appear in freely licensed photos, with the credit in the caption.</p>
<p>The cover is the retro-futurist robot with the weary face, kneeling at a 1950s World&rsquo;s Fair, studying its own hand while the crowd watches. The prompt to the model described the scene to hold three fears at once: the end of humanity, losing your job, the machine becoming conscious. The cover&rsquo;s record keeps the whole prompt. The face is Marvin&rsquo;s, my newsletter&rsquo;s character, and a sticker with my face sits beside the name.</p>
<h2>The tricks of turning posts into a book<span class="hx:absolute hx:-mt-20" id="the-tricks-of-turning-posts-into-a-book"></span>
    <a href="#the-tricks-of-turning-posts-into-a-book" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Turning a blog into a book is a list of mechanical conversions, and each one has a catch:</p>
<ul>
<li><strong>A link becomes a citation.</strong> Every external link became a bibliography entry, and the sentence has to stand without the link. A link to another post of mine became a cross-reference to the chapter that now covers it, or disappeared. Never a URL in the prose.</li>
<li><strong>&ldquo;Today&rdquo;, &ldquo;yesterday&rdquo;, &ldquo;last week&rdquo;, &ldquo;update:&rdquo;</strong> became absolute dates. The book will be read in 2028 too.</li>
<li><strong>Model versions, prices, benchmark scores</strong> stayed as dated snapshots (&ldquo;in September 2026, the best&hellip;&rdquo;), and when a later post superseded the number, the book tells the change instead of printing the old number.</li>
<li><strong>Code dumps, install steps, terminal screenshots</strong> were cut. At most a 3-to-8-line excerpt when the code is the point; the step-by-step went to an appendix.</li>
<li><strong>Post titles, which are made for search</strong> (&ldquo;Vibe Code: I built X in two days&rdquo;), became short literary titles, with the subject in the subtitle.</li>
<li><strong>Repetition across posts</strong>, the same thesis from many angles, is said once, in the right place, and later chapters build on it.</li>
<li><strong>Calls to action, &ldquo;subscribe&rdquo;, &ldquo;comment&rdquo;</strong>, cut.</li>
<li><strong>The sharp edge aims at the propaganda, never at the reader.</strong> The post &ldquo;You&rsquo;re an idiot if you believe&hellip;&rdquo; became a chapter about how the ads work. The reader who believed the ad is the person the book wants to help.</li>
<li><strong>Every technical term is explained once</strong>, at its first appearance in the book, and goes to the glossary.</li>
</ul>
<p>And the most important of all: the book reads like a first-person story, with the year as its spine. Information arrives when the narrative needs it, instead of following encyclopedia order. That&rsquo;s the opposite of how a blog is written, and it was the rule that gave the agents the most trouble.</p>
<h2>The English edition<span class="hx:absolute hx:-mt-20" id="the-english-edition"></span>
    <a href="#the-english-edition" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The English edition, <em>Competent Enough</em>, only started after I approved the Portuguese one. Each translated unit records the hash of the Portuguese file it came from, and wherever the book follows a post of mine that already had an English version on the blog, the translation uses my own English wording instead of translating again.</p>
<p><code>drift</code> also works per language: if I change a paragraph in Portuguese, it flags the English unit that went stale, and only the marked paragraphs are retranslated. Charts with text are regenerated in English from the same scripts, and the English cover is composed by script on top of the same art.</p>
<h2>Releasing is pushing a tag<span class="hx:absolute hx:-mt-20" id="releasing-is-pushing-a-tag"></span>
    <a href="#releasing-is-pushing-a-tag" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A release is a CHANGELOG entry and a <code>git push</code> of a <code>vX.Y.Z</code> tag. A GitHub Actions workflow runs the tests, builds both editions in every format, validates the EPUB, runs the audit and publishes the release with the files. It deletes every release except the two newest, and keeps the tags. That&rsquo;s how the official page always points at the current version.</p>
<p>The repository is public, and that brought its own catch: my home server notes are the source of some facts, and they&rsquo;re private. The provenance markers cite those files by alias, the alias map stays out of git, and a pre-push hook blocks any file or commit message containing a private repository name, host or IP.</p>
<h2>Copyediting: what the checking machine lets through<span class="hx:absolute hx:-mt-20" id="copyediting-what-the-checking-machine-lets-through"></span>
    <a href="#copyediting-what-the-checking-machine-lets-through" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Lint, doctor, page audit and tests catch structural problems. They let through what a book written by many agents, each seeing a few chapters, always suffers from: the same sentence or anecdote reused in three chapters, drifting tone, inconsistent terminology, agreement slips. For that there&rsquo;s a copyedit procedure, which runs once per version, in three steps from the cheapest to the most expensive.</p>
<p><strong>Step 1, mechanical and nearly free:</strong> the style report I mentioned above. Sequences of seven words or more that appear in more than one unit, meaning reused sentences and retold anecdotes; set phrases of four to six words used in many chapters, which are nice as callbacks and become tics when they repeat; a word used far more in one chapter than in the rest; term variants (&ldquo;e-mail&rdquo; and &ldquo;email&rdquo;, &ldquo;Open AI&rdquo; and &ldquo;OpenAI&rdquo;); and an agreement heuristic for Portuguese. The report is a worklist, and nothing changes on its own.</p>
<p><strong>Step 2, the straight-through read:</strong> one read-only agent per part of the book, each reading its units in order, start to finish, with a shared style sheet (names, spellings, terms, recurring phrases from step 1). Each produces a ranked report, editing nothing: typos and grammar first, then inconsistencies with the style sheet, repetition the reader would notice, passages a lay reader would stumble on, and pacing only in the worst cases. A script validates the reports, checks that every quoted passage really exists in the unit, numbers the items and summarizes.</p>
<p>Then comes the triage, done by me with an editor agent, and the pointed application of each approved item, under the same rules as the integration pass. A cheaper model does the proofreading; hard passages go to the strong model. Rough budget: two to three million tokens per language.</p>
<p>The most important rule of that step is &ldquo;facts get checked, not asked&rdquo;. Any item that turns on a number, date, name or tool behavior is settled by the editor against the source of truth before it reaches me: first the post pointed to by the paragraph&rsquo;s provenance marker, recomputing totals; then the code or data behind the claim, in my repositories; then public records.</p>
<p>When two sources disagree, the task is to find out why. &ldquo;653 commits in 8 projects&rdquo; versus &ldquo;692 in 4&rdquo; were two cuts of the same work, one of them without the newsletter&rsquo;s private repository, and the text now states its scope instead of picking a number. When the blog post itself is wrong, the book prints the correct figure and the error goes to a blog errata list, for me to fix at the source.</p>
<p>Only what no source can settle reaches me: an unpublished fact, intent (&ldquo;is this ironic?&rdquo;), a preference about a cut or a title, and a contradiction between two statements of mine with no record to break the tie. Each question comes with what was checked and what was found.</p>
<p><strong>Step 3, my own read.</strong> The last and the most valuable. The notes go into the same cycle of apply, check and propagate to the English edition.</p>
<p>The first round of that copyedit is what separates preview 2 from preview 3. Among what it caught: commit counts now state their scope, a &ldquo;more than a thousand&rdquo; that summed to 984, the Frank Investigator voting example that didn&rsquo;t match the code (figure redrawn), the David Sacks and Pirate Wires quotes in chapter 14 verified against the originals and corrected, Sam Altman&rsquo;s photo swapped for one from 2025. And in the English edition, a reader pass of its own after the re-sync: Portuguese calques rewritten, glossary terms used consistently, American quotation punctuation throughout.</p>
<h2>Fake readers, real feedback<span class="hx:absolute hx:-mt-20" id="fake-readers-real-feedback"></span>
    <a href="#fake-readers-real-feedback" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Copyediting checks the text. It lets through the question that matters in a book for lay readers: can the person I wrote it for read it to the end, understand it, and come out convinced? To answer that, the next pass was a review by simulated readers.</p>
<p>The book&rsquo;s preface has a section called &ldquo;Who I wrote this for&rdquo;. From it came five personas, each with a name, an age, a job and the fear that brought them to the book:</p>
<ul>
<li><strong>Marina</strong>, 38, an accountant in Belo Horizonte, read that her job &ldquo;ends in two years&rdquo;, reads on her phone at night and wants to know what to do on Monday;</li>
<li><strong>Roberto</strong>, 52, owns a hardware store, his 15-year-old saw a video about superintelligence and asked if it was true; suspicious of hype, of &ldquo;experts&rdquo; and of an author who shows off;</li>
<li><strong>Carla</strong>, 44, operations manager at a logistics company, the board hired consultants selling an &ldquo;AI transformation&rdquo;; she wants a decision she can take;</li>
<li><strong>Lucas</strong>, 24, a junior developer a year into the job, afraid he chose the wrong career;</li>
<li><strong>Helena</strong>, 61, a retired history teacher, no fear at all, came for the stories and loses patience with lists and manuals.</li>
</ul>
<p>One agent per persona, read-only, cheaper model, reads the whole book in order the way that person would. The instruction is explicit: you are a reader, the editor stays out of it; comma errors were already handled, report only what changes the reading experience. Each one returns a 1-to-5 score per chapter, a comment in the persona&rsquo;s voice (&ldquo;I finally get why the chatbot agrees with me&rdquo;, &ldquo;lost me in the benchmark tables&rdquo;), at most 35 annotations classified as confusing, boring, rewrite or logic, and cut candidates. It costs about 350K tokens per persona per full read.</p>
<p>An editor consolidates: the score matrix by chapter and persona and the pattern behind it, what readers loved (to protect in any edit), the logic items, checked against the text and the posts before making the list and fixed regardless of votes, and the clarity items ranked by how many personas raised them. A single persona&rsquo;s taste note is dropped. Then I decide, and recurring patterns become numbered rules in an editorial rules document, with their origin and how each is enforced.</p>
<blockquote>
  <p>The first read said what I suspected and gave it a measure: stories and practical tools work for everyone; the measurement-heavy middle, chapters 11 to 13, loses the non-programmers, averaging between 2.2 and 2.4. &ldquo;Sharp when he tells what happened to him, loses me when he tells what he measured&rdquo;, Helena summed up, for all five.</p>

</blockquote>
<p>And all five caught the same argument flaws. Chapter 20&rsquo;s conclusion went beyond its evidence: it said &ldquo;the numbers say it won&rsquo;t get smarter&rdquo; resting on a programming benchmark the same chapter calls saturated. Chapter 9 argued in a way that can never lose: every agent failure was the request&rsquo;s fault. Four of the five were sent to the wrong chapter by &ldquo;how to read&rdquo;.</p>
<p>Those became the first rules:</p>
<ul>
<li>every claim scoped to what was measured;</li>
<li>no argument that can&rsquo;t lose;</li>
<li>opinion marked as opinion;</li>
<li>the opposing side in its strongest form before rebutting;</li>
<li>the book obeys its own lessons.</li>
</ul>
<p>One round is not enough, because edits fix the old problem and create the new one. In round two, an apology placed next to a contradiction (&ldquo;I know this seems to clash with&hellip;&rdquo;) made all five readers notice a contradiction that three had previously missed. It became a rule: fix the design, and leave the apology out. So the process runs in rounds: read, edit, read again with the same personas on a fresh read, forbidden from opening the previous reports to avoid anchoring, and a script compares the rounds.</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th style="text-align: right">round 1</th>
          <th style="text-align: right">round 2</th>
          <th style="text-align: right">round 3</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>book average score</td>
          <td style="text-align: right">3.32</td>
          <td style="text-align: right">3.38</td>
          <td style="text-align: right">3.41</td>
      </tr>
      <tr>
          <td>logic annotations</td>
          <td style="text-align: right">73</td>
          <td style="text-align: right">53</td>
          <td style="text-align: right">51</td>
      </tr>
  </tbody>
</table>
<p>The average score is noisy (an untouched chapter swings 0.6 between reads), so the stopping criterion is different: the problems flagged stopped coming back and nothing new reaches three readers. In round three the curve flattened and the review stopped there, with a backlog for my own read. What changed along the way: about 8,000 words of lab notebook left the chapters for a new appendix, &ldquo;For programmers: the backstage&rdquo;, each paragraph carrying its provenance marker along; the reading list became an appendix; the Genesys PI section was parked, kept outside the book while verification is pending; chapter 19 got the title its argument supports; every chapter opens by orienting the reader before the first jargon; and the epilogue got a &ldquo;this week&rdquo; list per reader type. Cost of the three rounds: about 5 million tokens of reading plus about 3 million of editing and English re-sync.</p>
<h2>The narrator got a past<span class="hx:absolute hx:-mt-20" id="the-narrator-got-a-past"></span>
    <a href="#the-narrator-got-a-past" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>With the argument in place, the first person lacked substance. The book&rsquo;s narrator was the Akita of 2026, and I have thirty years of history that explain why I think what I think: the dot-com crash seen from inside, five years integrating SAP at large companies, the warnings about the hiring bubble I gave on video in 2019, 2020 and 2022, the &ldquo;Don&rsquo;t outsource your decisions&rdquo;. All of it is in the transcripts of the 149 episodes of <a href="https://www.youtube.com/@Akitando"target="_blank" rel="noopener">Akitando</a>, published on this blog between 2018 and 2023.</p>
<p>The process was the same as the rest of the book, in miniature. Extraction agents read 23 episodes in full, with a form: biographical facts with the verbatim quote and what would verify them, facts about the world, recurring positions in my words, and hooks, meaning the exact place in the book where one or two sentences of that history back a 2026 claim. From that came a narrator profile, which I confirmed line by line, and a plan with about 30 touches, most of them one to three sentences.</p>
<p>Before any touch, more than 140 claims taken from the episodes went through the fact-check. It corrected the book and corrected me: the hiring bubble started around 2010, with interest rates near zero, and my February post said 2014; the dot-com bubble burst between 2000 and 2002; the 2022 layoffs were around 165 thousand. And it found errors in old episodes the book doesn&rsquo;t even use, which went to a blog errata list.</p>
<p>The touches went where experience becomes evidence: the week in 2001 when my dot-com closed and a mentor called me into an SAP consultancy; the SAP years behind the claim that the model is blind to a company&rsquo;s private rules; the dated bubble warnings next to the admitted mistake, because in 2022 I expected a second leg down in 2023 that the AI wave cancelled. Two new appendices came out of it: &ldquo;Three bubbles&rdquo;, with the verified numbers of the dot-com crash, the zero-interest bubble and the AI wave, and &ldquo;How to study with AI at your side&rdquo;, from the channel&rsquo;s most watched episode.</p>
<p>Those episodes are background sources, and <code>drift</code> now watches them as it watches the 2026 posts. Then came a scoped check with the same five personas, only on the touched chapters, with three extra questions: does the narrator&rsquo;s history make the argument more convincing, and where? Does any passage read as showing off or &ldquo;I told you so&rdquo;? Does anything about the narrator contradict itself?</p>
<blockquote>
  <p>All five said yes to credibility, with a condition: the history convinces when it&rsquo;s evidence the reader can check, the dated warning next to the admitted mistake, and convinces less when it becomes a résumé, which clashes with the book itself, which says &ldquo;a résumé is not an argument&rdquo;. It became rule 21: the narrator&rsquo;s history comes in as evidence, and credentials stay out.</p>

</blockquote>
<p>Three or four readers flagged the same lines as showing off, and they went: &ldquo;The warnings have dates&rdquo;, &ldquo;more than thirty public repositories&rdquo;, &ldquo;the most watched on my channel&rdquo;. The self-deprecating lines and the admitted mistakes all counted in my favor. And the check found contradictions I hadn&rsquo;t seen myself: the preface said &ldquo;late 90s&rdquo; and chapter 18 said 1996; one chapter said &ldquo;eight months&rdquo; and another &ldquo;a year of daily use&rdquo;, and they were fixed one by one.</p>
<h2>Accessibility is part of the build too<span class="hx:absolute hx:-mt-20" id="accessibility-is-part-of-the-build-too"></span>
    <a href="#accessibility-is-part-of-the-build-too" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>An EPUB opening on a Kindle does not make it accessible. This book has dozens of diagrams, charts and tables. Without additional work, much of the argument simply disappears for anyone using a screen reader.</p>
<p>The pipeline now treats accessibility as a publishing contract. Each of the 55 figures, in both languages, has a short alternative text and a complete description of what the image communicates. In HTML and EPUB, the detailed description appears with the figure; in PDF, it becomes its semantic replacement without changing the layout. Tables have captions, and the EPUB now identifies where the main text, glossary, references and image credits begin in its semantic navigation. The authoring contract is <a href="https://github.com/akitaonrails/ai-book-2026/blob/main/docs/ACCESSIBILITY.md"target="_blank" rel="noopener">documented in the repository</a>.</p>
<p>This doesn&rsquo;t depend on my memory either. <code>rake check</code> rejects figures without both descriptions or with overly long alternative text. Every build validates both EPUBs with EPUBCheck, DAISY Ace and the project&rsquo;s own checks. The Kindle edition also goes through a cleanup of CSS and embedded icons that tend to cause problems in Amazon&rsquo;s readers, but the script refuses to remove any rule the content has come to depend on.</p>
<p>No automated tool can certify WCAG conformance or guarantee how every reader on the market will behave. Manual review remains mandatory. The difference is that accessibility is now part of the build, and every change has to preserve that contract.</p>
<h2>What remains mine<span class="hx:absolute hx:-mt-20" id="what-remains-mine"></span>
    <a href="#what-remains-mine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The repository records the first commit and the draft of every chapter on the same day, October 13. Those are the first ten percent, the ones that impress and say almost nothing about the rest. The other ninety percent are reading, cutting and correcting, and that part is mine. No chapter goes in without me reading and approving it, and what I send back to be redone goes through the same process.</p>
<p>Any of the good models of October 2026 would have written similar drafts, because the model became a commodity. What made the process work was what surrounds it: the inventory, the written contract, the automatic checker, the sources as oracle, the per-paragraph trail. It&rsquo;s the same old software engineering I defend in every chapter, applied to text.</p>
<blockquote>
  <p>The agents were competent enough to write the draft. Deciding what it said remained my job.</p>

</blockquote>
<p>And, once again: making a book with AI isn&rsquo;t a &ldquo;write me a book&rdquo; prompt and done. I had to invent the whole process and steer the agent to create every piece of it: the scripts, the tests, the consolidation of the posts, the narrative strategy, the goals, what stays and what goes, the copyedit, the fact-checking, the automated release. You need to know exactly what you want, and then the AI helps a lot. Whoever doesn&rsquo;t know what a book publishing process involves won&rsquo;t make a real book, and showing that was one of the goals I had when creating this example.</p>
<h2>Download it, read it, and tell me where I was wrong<span class="hx:absolute hx:-mt-20" id="download-it-read-it-and-tell-me-where-i-was-wrong"></span>
    <a href="#download-it-read-it-and-tell-me-where-i-was-wrong" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Both editions, straight from GitHub, no sign-up. The current version is the final 1.0.0, from October 17, with everything this text describes:</p>
<table>
  <thead>
    <tr><th>Edition</th><th>EPUB (Kindle, Kobo, Apple Books)</th><th>Screen PDF</th><th>Print PDF (6 × 9 in)</th></tr>
  </thead>
  <tbody>
    <tr><td>Competent Enough (EN)</td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competent-Enough.epub">EPUB</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competent-Enough-ebook.pdf">PDF</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competent-Enough.pdf">PDF</a></td></tr>
    <tr><td>Competente o Suficiente (PT-BR)</td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competente-o-Suficiente.epub">EPUB</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competente-o-Suficiente-ebook.pdf">PDF</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competente-o-Suficiente.pdf">PDF</a></td></tr>
  </tbody>
</table>
<p>The latest version, always, lives on the <a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener">book page</a> and on the <a href="https://github.com/akitaonrails/ai-book-2026/releases"target="_blank" rel="noopener">GitHub releases</a>.</p>
<p>It&rsquo;s a preview. There will be mistakes, and the process above exists so they get fixed in the right place. Found one, <a href="https://github.com/akitaonrails/ai-book-2026/issues"target="_blank" rel="noopener">open an issue</a>.</p>
]]></content:encoded><category>artificial-intelligence</category><category>coding-agents</category><category>open-source</category></item><item><title>AI Reverse Engineering: Is Adobe Dead?</title><link>https://akitaonrails.github.io/en/2026/10/13/ai-reverse-engineering-is-adobe-dead/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/10/13/ai-reverse-engineering-is-adobe-dead/</guid><pubDate>Tue, 13 Oct 2026 00:00:00 -0300</pubDate><description>&lt;p&gt;PhotoCraft exists. REA exists. Recomps and decomps of old games ship every day. Therefore: Adobe is dead, no binary is sacred, and programmers are finished.&lt;/p&gt;
&lt;p&gt;That was the week on X, and if you only read headlines, it&amp;rsquo;s a reasonable conclusion. This text is for anyone who wants to know what each of those things actually does.&lt;/p&gt;
&lt;p&gt;It blew up on the 9th, when the account below summed up what Brandon Thomas, a developer from Atlanta, had been publishing since late September: seven open source clones of Adobe&amp;rsquo;s main products, written in Rust with help from Claude Opus 5.5. Photoshop, Illustrator, Premiere, Lightroom, After Effects, InDesign, Acrobat. All free, all &amp;ldquo;clean room&amp;rdquo;, without a single line of Adobe code. This is the post that went viral:&lt;/p&gt;</description><content:encoded><![CDATA[<p>PhotoCraft exists. REA exists. Recomps and decomps of old games ship every day. Therefore: Adobe is dead, no binary is sacred, and programmers are finished.</p>
<p>That was the week on X, and if you only read headlines, it&rsquo;s a reasonable conclusion. This text is for anyone who wants to know what each of those things actually does.</p>
<p>It blew up on the 9th, when the account below summed up what Brandon Thomas, a developer from Atlanta, had been publishing since late September: seven open source clones of Adobe&rsquo;s main products, written in Rust with help from Claude Opus 5.5. Photoshop, Illustrator, Premiere, Lightroom, After Effects, InDesign, Acrobat. All free, all &ldquo;clean room&rdquo;, without a single line of Adobe code. This is the post that went viral:</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">AI is now being used to recreate Adobe's software, a developer has released seven free, open-source apps as clean-room alternatives to Adobe's main tools:<br><br>- PhotoCraft → Photoshop<br>- VectorCraft → Illustrator<br>- FilmCraft → Premiere Pro<br>- LightCraft → Lightroom<br>- EffectCraft → After Effects<br>- DesignCraft → InDesign<br>- PrintCraft → Acrobat Pro<br><br>Built in Rust with help from Claude Opus 5.5, they run on Windows, Linux, and macOS under MIT/Apache licenses without using Adobe's source code.</p>&mdash; Pirat_Nation (@Pirat_Nation) <a href="https://twitter.com/Pirat_Nation/status/2108437553615425881">October 9, 2026</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>The same week, <a href="https://github.com/morluto/rea"target="_blank" rel="noopener">REA</a>, &ldquo;Reverse Engineer Anything&rdquo;, passed 100K stars on GitHub, gaining tens of thousands a day. The pitch on its page: &ldquo;see a feature in an app that you want in your own product? Ask your agent to investigate it with REA and build a version for your project&rdquo;.</p>
<p>And anyone who follows retro gaming knows 2026 is the year that keeps on giving. There&rsquo;s a <a href="https://docs.google.com/spreadsheets/d/1MT_xMPlKNbyhANRUMzOH94J3ybeF0b1Ws8F0kb-_598/edit"target="_blank" rel="noopener">community spreadsheet</a> trying to list the unofficial PC ports, around 100 games from Ship of Harkinian to Skate 3, and it&rsquo;s always behind. The <a href="https://www.youtube.com/@VideoGameEsoterica"target="_blank" rel="noopener">Video Game Esoterica</a> channel publishes a new port almost daily: Time Crisis decompiled from the arcade board, Daytona USA, Bloodborne.</p>
<p>The Xbox One version of <a href="https://almost-there-games.itch.io/azimuth"target="_blank" rel="noopener">Forza Horizon 2</a>, stuck there since 2014, runs on Windows. <a href="https://github.com/boykopovar/AnyPS5"target="_blank" rel="noopener">AnyPS5</a> promises to convert PS5 executables into native PC binaries, and PS5 emulators like KytyPS5 and SharpEmu already <a href="https://www.invenglobal.com/articles/26860/astro-bot-boots-on-pc-as-ps5-emulation-makes-rapid-progress"target="_blank" rel="noopener">run Astro Bot</a> with actual gameplay. Much of it with AI in the loop, some of it openly vibe-coded.</p>
<p>Hence the consensus: programming, in general, is over. Every binary is reversible and reusable, just point the agent at it. My position is that it did get much easier, that it&rsquo;s still nowhere near the silver bullet people imagine, and that the engine behind it, the LLM, <a href="/en/2026/10/12/llms-agents-competent-enough/">stopped growing exponentially</a>. The rest of the text is the reasons.</p>
<blockquote>
  <p><strong>TL;DR:</strong> reverse engineering is a 40-year-old discipline with mature tooling, and AI sped up its grunt work, especially in retro, where the binary is available, tiny, and the target doesn&rsquo;t move. The Adobe clones are alphas with hundreds of open bugs and pretty screenshots. REA is a toolbox that requires the binary in hand, Ghidra or IDA installed, and a lot of tokens. What&rsquo;s worth money today doesn&rsquo;t even have a binary: it&rsquo;s SaaS, cloud, manufacturer partnerships and decades of color science. Rewriting Bun, with the project&rsquo;s author and 64 agents, cost US$ 165K. Jump to the <a href="#reverse-engineering-wasnt-born-last-week">timeline</a>, to <a href="#what-rea-actually-does">REA</a>, to the <a href="#photocraft-pretty-screenshot-alpha-inside">Adobe clones</a>, to the <a href="#the-bun-case-what-it-costs-to-rewrite-big-software">Bun case</a>, to why <a href="#why-retro-moves-so-fast">retro moves fast</a> or to the <a href="#answering-the-list-from-the-top">answers at the end</a>.</p>

</blockquote>
<h2>First of all: I don&rsquo;t like Adobe<span class="hx:absolute hx:-mt-20" id="first-of-all-i-dont-like-adobe"></span>
    <a href="#first-of-all-i-dont-like-adobe" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>To be clear about where I&rsquo;m speaking from. I hate Adobe&rsquo;s business practices as much as anyone. I was a paying customer for years, used Photoshop and Premiere extensively, plus Lightroom and After Effects, and left for the same reasons everybody leaves: mandatory subscription, cancellation fees, prices going up with nothing in return.</p>
<p>And it&rsquo;s precisely because I used them in depth that I know the size of what&rsquo;s inside those boxes. Whoever thinks Photoshop is layers, crop and text never needed a color proof for a print shop, never opened a camera RAW whose color profile Adobe has maintained for twenty years, never did the conform on cinema footage, the work of gathering the camera&rsquo;s raw material for finishing. I&rsquo;ll get there, after the basics.</p>
<h2>Reverse engineering wasn&rsquo;t born last week<span class="hx:absolute hx:-mt-20" id="reverse-engineering-wasnt-born-last-week"></span>
    <a href="#reverse-engineering-wasnt-born-last-week" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every emulator you&rsquo;ve ever used exists because someone opened up hardware, disassembled a binary, sniffed a protocol and, in some cases, broke cryptography. The discipline has case law, commercial tooling and decades of history. A condensed timeline, with the milestones that matter most:</p>
<ul>
<li><strong>1982 to 1984</strong>: Compaq reverse engineers the IBM PC BIOS, and in 1984 Phoenix sells a licensable BIOS built in a clean room, by a team that only read the specification. The PC compatible industry is born. <a href="https://en.wikipedia.org/wiki/Phoenix_Technologies"target="_blank" rel="noopener">Source</a>.</li>
<li><strong>1992</strong>: Andrew Tridgell creates Samba by sniffing SMB packets. The same year, <a href="https://www.copyright.gov/fair-use/summaries/segaenters-accolade-9thcir1992.pdf"target="_blank" rel="noopener">Sega v. Accolade</a> and <a href="https://www.copyright.gov/fair-use/summaries/atari-nintendo-fedcir1992.pdf"target="_blank" rel="noopener">Atari v. Nintendo</a> establish in the US that disassembling code to reach functional elements is fair use (Atari lost its own case for another reason: it lied to the Copyright Office to get the source).</li>
<li><strong>1993</strong>: Wine begins, which becomes the foundation of Proton and of every Windows game that runs on the Steam Deck today.</li>
<li><strong>1999</strong>: UltraHLE runs commercial N64 games at full speed; bleem! emulates the PS1, Sony sues and loses the injunctions, and bleem! folds anyway in 2001; DeCSS breaks DVD protection.</li>
<li><strong>2000</strong>: <a href="https://law.resource.org/pub/us/case/reporter/F3/203/203.F3d.596.99-15852.html"target="_blank" rel="noopener">Sony v. Connectix</a> rules that copying the PS1 BIOS to build an emulator is fair use.</li>
<li><strong>2002 and 2003</strong>: PCSX2 and Dolphin are born, the two emulators that twenty years later are still the reference.</li>
<li><strong>2007</strong>: the iPhone is opened eleven days after launch. The European Commission forces Microsoft to document its network protocols, and the <a href="https://fsfe.org/news/2007/news-20071220-01.html"target="_blank" rel="noopener">Samba team receives the documentation</a> for 10,000 euros.</li>
<li><strong>2010</strong>: the fail0verflow group shows at 27C3 that Sony signed the PS3 firmware with a fixed nonce, exposing the private key (the nonce is the number that should be random in every signature). Days later, already in 2011, geohot publishes the key, Sony sues and settles in March.</li>
<li><strong>2011 and 2013</strong>: RPCS3 (PS3) and Xenia (Xbox 360) are born, the two hardest emulators ever built, for reasons I&rsquo;ll explain.</li>
<li><strong>2019</strong>: the NSA releases <a href="https://github.com/NationalSecurityAgency/ghidra"target="_blank" rel="noopener">Ghidra</a> as open source. The Super Mario 64 decompilation leaks and goes public, and the PC port appears the following year.</li>
<li><strong>2021 and 2022</strong>: Ocarina of Time 100% decompiled after almost two years of work; Ship of Harkinian becomes the reference port.</li>
<li><strong>2024</strong>: Mr-Wiseguy releases <a href="https://github.com/Zelda64Recomp/Zelda64Recomp/releases"target="_blank" rel="noopener">Zelda 64: Recompiled</a>, the first showcase of N64 static recompilation.</li>
<li><strong>2025</strong>: Sonic Unleashed Recompiled brings the same trick to the Xbox 360, converting PowerPC to C++ and shaders to HLSL.</li>
</ul>
<p>Notice that the current phase, decomp and recomp at scale, starts in 2019, well before any coding agent. AI joined an assembly line that already existed.</p>
<h3>The tools<span class="hx:absolute hx:-mt-20" id="the-tools"></span>
    <a href="#the-tools" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The tooling is mature too, and much of it is free:</p>
<ul>
<li><a href="https://hex-rays.com/ida-pro"target="_blank" rel="noopener">IDA Pro</a> (Hex-Rays), the reference commercial disassembler and decompiler, from one thousand to almost nine thousand euros a year, with a free version limited to x86.</li>
<li><a href="https://github.com/NationalSecurityAgency/ghidra"target="_blank" rel="noopener">Ghidra</a>, the NSA&rsquo;s open answer, with a decompiler and scripting, Apache 2.0.</li>
<li><a href="https://binary.ninja/"target="_blank" rel="noopener">Binary Ninja</a>, with a free edition and licenses from 200 to 3,500 dollars.</li>
<li><a href="https://github.com/radareorg/radare2"target="_blank" rel="noopener">radare2</a> and <a href="https://github.com/rizinorg/cutter"target="_blank" rel="noopener">Cutter</a>, the GUI for rizin, which is a radare2 fork: the open command line and the open interface.</li>
<li><a href="https://github.com/x64dbg/x64dbg"target="_blank" rel="noopener">x64dbg</a> and <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/"target="_blank" rel="noopener">WinDbg</a> on Windows, <a href="https://www.sourceware.org/gdb/"target="_blank" rel="noopener">GDB</a> everywhere else.</li>
<li><a href="https://frida.re/"target="_blank" rel="noopener">Frida</a>, to inject code into a live process and watch what it does.</li>
<li><a href="https://github.com/skylot/jadx"target="_blank" rel="noopener">JADX</a> for Android and <a href="https://github.com/icsharpcode/ILSpy"target="_blank" rel="noopener">ILSpy</a> for .NET.</li>
</ul>
<p>Keep this list in mind. REA, which we&rsquo;ll get to shortly, is a wrapper around it.</p>
<h2>How a binary gets taken apart, in practice<span class="hx:absolute hx:-mt-20" id="how-a-binary-gets-taken-apart-in-practice"></span>
    <a href="#how-a-binary-gets-taken-apart-in-practice" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In principle, every binary is reversible. The processor has to be able to execute it, so the instructions are in there. The path is always the same:</p>
<ol>
<li><strong>Disassemble</strong>: the binary becomes assembly, one machine instruction per line. This is mechanical.</li>
<li><strong>Decompile</strong>: the assembly becomes something resembling C. Ghidra and IDA do this reasonably well, with a lot of noise.</li>
<li><strong>Recover what the compiler threw away</strong>: variable names, function names, types, structures, comments. None of it survives compilation. This is the real work, and it&rsquo;s human.</li>
<li><strong>Refactor</strong> until it becomes code a person can read, maintain and port.</li>
</ol>
<p>The N64 decomp projects take step 4 all the way: their C code, recompiled, produces the original ROM byte for byte. That&rsquo;s how Super Mario 64 became a project with 135K lines of game C code (around 100K of actual code, plus half a million lines of generated level and model data), and Ocarina of Time passed 430K lines. Static recompilation skips part of this: it translates the original processor&rsquo;s instructions into generic C, without trying to understand them, and replaces only the parts that talk to the hardware. It&rsquo;s faster and the result is less readable.</p>
<h3>&ldquo;But can&rsquo;t the AI just read the binary directly?&rdquo;<span class="hx:absolute hx:-mt-20" id="but-cant-the-ai-just-read-the-binary-directly"></span>
    <a href="#but-cant-the-ai-just-read-the-binary-directly" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Someone always asks: if it&rsquo;s AI, why go through C? Let the model read the binary and build on top of it. The short answer is that an LLM only knows what was in its training corpus, and a corpus of binaries paired with source code is scarce, because no human has written production assembly in decades.</p>
<p>The long answer is that the literature exists, and it&rsquo;s instructive precisely because it&rsquo;s modest. The lineage runs from 2018 neural networks to models like <a href="https://arxiv.org/abs/2305.12520"target="_blank" rel="noopener">SLaDe</a> (200 million parameters, one per architecture and optimization level), <a href="https://arxiv.org/abs/2403.05286"target="_blank" rel="noopener">LLM4Decompile</a> (up to 33 billion) and <a href="https://arxiv.org/abs/2311.13721"target="_blank" rel="noopener">Nova</a>. Meta published an <a href="https://arxiv.org/abs/2407.02524"target="_blank" rel="noopener">LLM Compiler</a> that translates assembly into LLVM IR. The best results, on isolated benchmark functions, hover around 60 to 65% of code that runs again and gives the same result, dropping sharply when the compiler optimized with -O3.</p>
<p>Two recent studies show the real state of things. <a href="https://arxiv.org/abs/2505.11340"target="_blank" rel="noopener">DecompileBench</a>, with 23K real functions, found that LLM-based decompilers produce more readable code with half the functional correctness of commercial decompilers. And a <a href="https://arxiv.org/abs/2609.05370"target="_blank" rel="noopener">September 2026 paper</a> measured that LLM refinement of Ghidra output raises the compilation rate from 75% to 90% and drops behavioral fidelity from 74% to 62%, with up to around 10% of functions with known vulnerabilities no longer reproducing the flaw, meaning the bug vanished without anyone asking.</p>
<blockquote>
  <p>Summing up what exists: small models, function by function, almost only x86-64 Linux, and the best ones are refinement layers on top of Ghidra, which keeps the classic decompiler in the loop. No emulator, no game, no whole program has been neurally recompiled. Until someone invents that, you work with reality, and reality includes the intermediate layer of programming language and compiler.</p>

</blockquote>
<p>The AI assistants that exist for this in production confirm the design: <a href="https://plugins.hex-rays.com/aidapal"target="_blank" rel="noopener">aiDAPal</a>, an IDA plugin by Atredis, Binary Ninja&rsquo;s Sidekick, the MCP servers for Ghidra. All of them are an LLM naming variables and explaining functions on top of what the traditional decompiler produced.</p>
<h2>What REA actually does<span class="hx:absolute hx:-mt-20" id="what-rea-actually-does"></span>
    <a href="#what-rea-actually-does" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I cloned <a href="https://github.com/morluto/rea"target="_blank" rel="noopener">REA</a> and read the code. It&rsquo;s an MCP server and a TypeScript CLI that wraps the tools from the list above and exposes them to your coding agent: Ghidra, Hopper, IDA, JADX, Frida, Wakaru for obfuscated JavaScript, Playwright to capture what a website does. The agent asks, REA runs the tool and returns pseudocode, call graphs, strings and IPC traces, each result with an evidence record and a list of limitations.</p>
<p>I had already done that flow by hand, months before REA went viral. In July I <a href="/en/2026/07/08/fable-5-analyze-tiktok-clash-of-kings-govbr-fingerprint/">had Fable 5 analyze the code of TikTok, Clash of Kings and gov.br</a>: I downloaded the APKs, unzipped them (an APK is a zip), ran JADX on the <code>.dex</code> files and let the model read the Java that came out the other side. It was enough to see the endpoints, the permissions, the embedded SDKs and how each app builds the device fingerprint, that persistent identifier that survives clearing data and reinstalling. TikTok came out as industrial-grade collection, armored against auditing; gov.br, as the example of how to do it right.</p>
<p>The three lessons from that post apply to all of REA. Android is far too easy to decompile, and even so the result serves only static analysis, because recompiling the app is out of reach: the names come scrambled by obfuscation, resources and signing keys are missing. The most sensitive part lives in native code, <code>.so</code> files in C and C++, which decompile into nothing readable, and in TikTok that&rsquo;s exactly where the core sits. And what came out of that work was a report on what the app does, with caveats, and no TikTok clone. REA packages that same flow into an MCP server; the walls stay in the same place.</p>
<p>The judgment is supplied by the LLM you already pay for. REA supplies the deterministic plumbing and the provenance. The phrase &ldquo;automates the heuristics of reverse engineering&rdquo;, which circulates out there, appears nowhere in the repository; the description the project itself uses is agent-driven reverse engineering with traceable evidence.</p>
<p>What it requires: the artifact on your machine (native binary, Electron app, .NET assembly, APK, firmware, network capture), Node 22.19 or later, and the heavy tools installed at your own expense. Ghidra is free; IDA, Hopper and JEB the README tells you to buy. There&rsquo;s no REA API key because it runs locally, and the token cost lands entirely on your agent subscription.</p>
<p>And that cost is the detail nobody mentions. REA&rsquo;s MCP tool catalog is 2.3 MB of JSON, which goes into the agent&rsquo;s context. The project itself publishes an <a href="https://github.com/morluto/rea/tree/main/experiments/analysis-efficiency"target="_blank" rel="noopener">experiment</a> in which analyzing SQLite compiled to WASM, on the default path, took 42 tool calls, five minutes and 300K input tokens. A full inventory of an Electron app like Obsidian returns almost 1 MB of JSON.</p>
<p>There&rsquo;s an open issue complaining that inspecting an ordinary Mac app returns 80K to 230K tokens in one go.</p>
<p>The project is serious and goes far: six months, 2,600 commits, a thousand test files, version 6.4 released on October 11. It&rsquo;s also unstable: 190 open issues, several breaking changes per minor release, subsystems marked experimental.</p>
<p>The limits are written in the repository itself. CONTRIBUTING excludes breaking DRM, anticheat, licensing and commercial protections. The DISCLAIMER warns that decompilation, reconstruction and AI-assisted analysis &ldquo;may be incomplete or incorrect&rdquo;. And even the internal instructions for generating the website&rsquo;s figures say, in so many words: &ldquo;never imply REA automatically clones a program&rdquo; and &ldquo;never say full reconstruction, exact game clone, or automatic source recovery&rdquo;.</p>
<blockquote>
  <p>REA is a good toolbox for someone who already knows how to do reverse engineering and wants an agent holding Ghidra. It isn&rsquo;t the &ldquo;copy this app for me&rdquo; button. The people who wrote the project are the first to say so.</p>

</blockquote>
<h2>PhotoCraft: pretty screenshot, alpha inside<span class="hx:absolute hx:-mt-20" id="photocraft-pretty-screenshot-alpha-inside"></span>
    <a href="#photocraft-pretty-screenshot-alpha-inside" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The <a href="https://github.com/storytold/photocraft"target="_blank" rel="noopener">PhotoCraft repository</a> was created on September 30. In two weeks, 54K stars, 8 releases and, as I write, more than 800 open issues. The README badge says &ldquo;early alpha&rdquo;, and Brandon Thomas himself, quoted by Gizmodo, said it&rsquo;s nowhere close to ready. The press that tested it reached the same conclusion: Gizmodo called it a &ldquo;glitchy, but real, Photoshop&rdquo;, and OMG Ubuntu &ldquo;a superficial facsimile with pronounced flaws&rdquo;.</p>
<p>The issues tell the technical story:</p>
<ul>
<li>Any image above 8,192 pixels leaves the GPU compositor and falls back to the CPU, with a 6 GB memory peak, because that&rsquo;s the egui-wgpu texture limit (<a href="https://github.com/storytold/photocraft/issues/49"target="_blank" rel="noopener">issue 49</a>, already closed, and the ones that came after it, <a href="https://github.com/storytold/photocraft/issues/1015"target="_blank" rel="noopener">1015</a> and <a href="https://github.com/storytold/photocraft/issues/4017"target="_blank" rel="noopener">4017</a>).</li>
<li>A 12 megapixel photo needs almost 800 MB just to open, adjust and export from the command line (<a href="https://github.com/storytold/photocraft/issues/1637"target="_blank" rel="noopener">issue 1637</a>).</li>
<li>Color management is rudimentary: a global working space only, instead of per document, and no view transform (<a href="https://github.com/storytold/photocraft/issues/321"target="_blank" rel="noopener">issue 321</a>). Eighteen issues mention CMYK, fifteen mention ICC profiles.</li>
<li>Almost a hundred open issues mention PSD. Hue/Saturation layers composite differently from Photoshop, and saving over the file overwrites the original&rsquo;s correct merged image (<a href="https://github.com/storytold/photocraft/issues/4089"target="_blank" rel="noopener">issue 4089</a>).</li>
<li>Fifty open issues mention &ldquo;crash&rdquo;.</li>
</ul>
<p>The interface resembles Photoshop, so the screenshot is shareable, and whoever sees the screenshot assumes it&rsquo;s a carbon copy. That&rsquo;s expected in a two-week-old alpha. With interest, time and contributions, part of this gets fixed. And then the contributors will discover something the N64 projects never faced.</p>
<blockquote>
  <p>PhotoCraft today is that Ferrari replica built on top of a VW Beetle: the body has the right shape, you take a photo and most people say &ldquo;wow, a Ferrari&rdquo;. Then you turn the key and out comes the Beetle engine. If the photo got you hyped, that&rsquo;s on you.</p>

</blockquote>
<h2>The target moves<span class="hx:absolute hx:-mt-20" id="the-target-moves"></span>
    <a href="#the-target-moves" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Decompiling 1998&rsquo;s Zelda is aiming at a stationary target. Nintendo isn&rsquo;t going to release Ocarina of Time 2026 with a new file format. Copying a live product is another conversation, and we&rsquo;ve seen this movie before.</p>
<p>In the 90s and 2000s the target was Microsoft Office. StarOffice became OpenOffice in 2000 and LibreOffice in 2010, and all of them spent years chasing a binary format, .doc, that changed from version to version and only got a public specification in 2008, when the game was already over. The proven part of that story is in the court cases: the European Commission fined Microsoft <a href="https://ec.europa.eu/commission/presscorner/detail/en/ip_04_382"target="_blank" rel="noopener">497 million euros in 2004</a> for refusing to supply interoperability information, and <a href="http://news.bbc.co.uk/2/hi/business/7266629.stm"target="_blank" rel="noopener">899 million in 2008</a> for failing to comply. .docx only became an ISO standard in 2008, in a <a href="https://en.wikipedia.org/wiki/Standardization_of_Office_Open_XML"target="_blank" rel="noopener">vote so controversial</a> that countries formally protested.</p>
<p>It took more than ten years. And when the format finally opened, Office no longer mattered the same way. The value moved elsewhere: today it&rsquo;s <a href="https://office365itpros.com/2024/01/31/office-365-reaches-400-million/"target="_blank" rel="noopener">400 million paid Office 365 seats</a>, <a href="https://www.googlecloudpresscorner.com/2025-12-04-Google-Workspace-Study-Reveals-More-Than-90-of-Rising-Leaders-Want-AI-With-Personalization"target="_blank" rel="noopener">3 billion Google Workspace users</a> and around <a href="https://prodesigntools.com/number-of-creative-cloud-subscribers.html"target="_blank" rel="noopener">41 million Creative Cloud subscribers</a>. Nobody wants to install that on a desktop, and so nobody has the binary.</p>
<blockquote>
  <p>Reverse engineering Google Docs means rewriting the product from scratch looking only at the interface, because the code that matters never leaves the server. After the world moved to SaaS, most proprietary software became a walled garden with no binary. No binary, nothing to disassemble.</p>

</blockquote>
<p>You can build versions of it, of course. <a href="https://immich.app/"target="_blank" rel="noopener">Immich</a> replaces Google Photos for a person or a family: phone backup, face recognition, semantic search, all on your server. What it doesn&rsquo;t replicate is the infrastructure and the training corpus that make Google&rsquo;s search Google&rsquo;s search. And Adobe made the same migration, in pieces.</p>
<h2>Photoshop is far more than layers and crop<span class="hx:absolute hx:-mt-20" id="photoshop-is-far-more-than-layers-and-crop"></span>
    <a href="#photoshop-is-far-more-than-layers-and-crop" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the part I know from having paid for it. The features that sell subscriptions today don&rsquo;t even run on your computer.</p>
<p>Generative Fill and Generative Expand run on Firefly, in the cloud, and consume <a href="https://helpx.adobe.com/creative-cloud/apps/generative-ai/generative-credits-faq.html"target="_blank" rel="noopener">generative credits</a>. Several Neural Filters, according to <a href="https://helpx.adobe.com/photoshop/using/neural-filters.html"target="_blank" rel="noopener">Adobe&rsquo;s own documentation</a>, need an internet connection because the processing happens on Adobe&rsquo;s servers. AI object selection has had, since 2020, an option to process in the cloud for a refined result. All of this is code that doesn&rsquo;t exist on your machine for anyone to disassemble.</p>
<p>Then comes what is in the binary, but took decades and partnerships to exist. Camera Raw carries <a href="https://helpx.adobe.com/camera-raw/desktop/dng-and-file-formats/supported-lenses.html"target="_blank" rel="noopener">lens correction profiles</a> and per-camera color profiles for hundreds of models, built over twenty years and updated with every release. No clone guesses that. Either you have the data or you don&rsquo;t.</p>
<p>And there&rsquo;s color science. The example I always remember is GIMP and CMYK.</p>
<p>GIMP was born in 1995. The first native support for CMYK files arrived in <a href="https://www.gimp.org/news/2022/08/27/gimp-2-99-12-released/"target="_blank" rel="noopener">2022</a>, and only for import and export, with pixels always in RGB. <a href="https://www.cgchannel.com/2025/03/gimp-3-0-is-out/"target="_blank" rel="noopener">GIMP 3.0, from 2025</a>, still has no CMYK editing mode. It&rsquo;s on the <a href="https://developer.gimp.org/core/roadmap/"target="_blank" rel="noopener">roadmap</a> as work in progress.</p>
<p>Thirty years of an open project, with good and motivated people, and the print shop still asks for Photoshop. That&rsquo;s the size of the color science hole, and no coding agent invents color science: it reproduces what&rsquo;s in the training data.</p>
<p>Why did it take so long, if it was the most requested feature? Because GIMP&rsquo;s core was born with 8-bit-per-channel RGB baked into every layer, blend mode and filter. Supporting another color model meant rewriting the entire pixel engine, the migration to GEGL, which took the better part of a decade and was only finished in <a href="https://www.gimp.org/release-notes/gimp-2.10.html"target="_blank" rel="noopener">GIMP 2.10, in 2018</a>. CMYK could only start after that.</p>
<p>And CMYK is a family of device profiles, with four inks, a per-printer ICC profile, ink limits and black generation rules, and editing in it means the whole pipeline has to compute in a subtractive four-channel model and round-trip through the profiles without drifting. A single developer, however good a programmer, without experience in this specific field will struggle to implement it, because the knowledge lives in print shops and color labs, and almost none of it is in a training corpus. In GIMP, the people who carried it forward were contributors who understand printing, and even then it took years. No new tool shortcuts that kind of knowledge.</p>
<p>And then there&rsquo;s the layer that isn&rsquo;t even technical: commercial licensing. Print-shop color is Pantone, and Pantone is a proprietary library. No open project can ship the palettes; the Inkscape developers <a href="https://lists.inkscape.org/hyperkitty/list/inkscape-devel@lists.inkscape.org/message/DOXDMUAPHORC4HEXPF37LYBQH6SSQ2M5"target="_blank" rel="noopener">reached that conclusion in 2005</a>, and <a href="https://www.linux.com/news/pantone-and-free-software/"target="_blank" rel="noopener">Linux.com explained the legal risk</a> around the same time. Adobe itself felt it in 2022: when Pantone changed its business model, the libraries <a href="https://petapixel.com/2022/10/28/you-have-to-pay-a-subscription-to-use-pantone-colors-in-photoshop-now"target="_blank" rel="noopener">were pulled from Photoshop, Illustrator and InDesign</a>, old files started opening with their Pantone colors replaced by black, and anyone who needs them pays for a separate plugin subscription. If even Adobe, paying, didn&rsquo;t escape, imagine a clone that runs on goodwill.</p>
<h3>Video is worse<span class="hx:absolute hx:-mt-20" id="video-is-worse"></span>
    <a href="#video-is-worse" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In Premiere, After Effects and DaVinci Resolve, the problem multiplies. A cinema camera doesn&rsquo;t deliver video, it delivers raw data on its own logarithmic curve: ARRI&rsquo;s LogC4, RED&rsquo;s IPP2. To turn that into an image you need the manufacturer&rsquo;s transforms, and RED ships its own in an <a href="https://community.acescentral.com/t/red-ipp2-color-workflows/1055"target="_blank" rel="noopener">SDK</a> that the editors integrate and update with every version. ACES, the industry&rsquo;s neutral standard, depends on input transforms supplied by each manufacturer.</p>
<p>Blackmagic gives Resolve away for free and it decodes ARRIRAW and R3D. It does that because it pays for the SDK and the partnership on your behalf. An agent-built clone, &ldquo;guessing&rdquo; how the Alexa&rsquo;s image should look, produces an image that doesn&rsquo;t match the reference monitor, and in cinema that means it&rsquo;s useless. That knowledge isn&rsquo;t in any training corpus: it&rsquo;s in contracts.</p>
<h2>The Bun case: what it costs to rewrite big software<span class="hx:absolute hx:-mt-20" id="the-bun-case-what-it-costs-to-rewrite-big-software"></span>
    <a href="#the-bun-case-what-it-costs-to-rewrite-big-software" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For a sense of the order of magnitude, the best public data point there is comes from Bun. In May 2026, Jarred Sumner rewrote the entire runtime from Zig to Rust using agents, and in July <a href="https://bun.com/blog/bun-in-rust"target="_blank" rel="noopener">published the numbers</a>:</p>
<ul>
<li>535K lines of Zig in 1,448 files became a one-million-line Rust diff, in 11 days.</li>
<li>Up to 64 Claude instances in parallel, 24 hours a day, every line reviewed by two adversarial agents and a fixer.</li>
<li>5.9 billion uncached input tokens, 690 million output tokens, 72 billion cache reads: <strong>around US$ 165K</strong> at API prices.</li>
<li>16K compiler errors fixed by 64 agents before CI went green on six platforms.</li>
<li>The existing test suite, with more than a million assertions, passed 100% before the merge.</li>
</ul>
<p>Read again what made it possible:</p>
<ul>
<li>the project&rsquo;s original author at the controls</li>
<li>a complete, working source code as reference</li>
<li>a test suite with a million assertions serving as the oracle</li>
<li>unlimited budget, because Bun has belonged to Anthropic since December 2025, and a pre-release version of Claude Fable 5</li>
</ul>
<p>Sumner estimates three engineers with full context would have needed a year.</p>
<p>Now take each of those advantages away. PhotoCraft doesn&rsquo;t have the Photoshop source to port, it has to invent. It doesn&rsquo;t have a test suite that says &ldquo;this matches Photoshop&rdquo;. It doesn&rsquo;t have Photoshop&rsquo;s author.</p>
<p>And Photoshop is a 36-year-old product whose disk requirements Adobe lists between <a href="https://helpx.adobe.com/photoshop/desktop/get-started/technical-requirements-installation/adobe-photoshop-on-desktop-technical-requirements.html"target="_blank" rel="noopener">10 and 100 GB</a>, against a JavaScript runtime. Even without knowing the size of Adobe&rsquo;s codebase, we&rsquo;re talking about a bigger target, with no reference, no oracle and no owner. Orders of magnitude above US$ 165K, and even then it would be an approximation.</p>
<h2>Why retro moves so fast<span class="hx:absolute hx:-mt-20" id="why-retro-moves-so-fast"></span>
    <a href="#why-retro-moves-so-fast" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If it&rsquo;s so hard, why does an old game port ship every day? Because retro stacks up every advantage the rest doesn&rsquo;t have.</p>
<p><strong>The binary is available and tiny.</strong> Super Mario Bros. on the NES: 40 KB. Super Mario 64: 8 MB. Ocarina of Time and Majora&rsquo;s Mask: 32 MB each. A whole PS1 CD: 650 MB.</p>
<p>Compare with <a href="https://store.steampowered.com/app/1086940/Baldurs_Gate_3/"target="_blank" rel="noopener">Baldur&rsquo;s Gate 3</a>, 150 GB, or with the <a href="https://support.activision.com/black-ops-6/articles/pc-system-requirements-for-black-ops-6"target="_blank" rel="noopener">latest Call of Duty</a>, above 100 GB. That&rsquo;s three or four orders of magnitude, and the scope shrinks along with it: a 1996 game has a handful of systems, not a physics engine with networking, a store and anticheat.</p>
<p><strong>The technology is old and documented.</strong> Twenty-five years of community have already mapped the N64, PS1 and SNES hardware instruction by instruction. The agent discovers nothing; it speeds up work that already has a map. It&rsquo;s the same pattern I <a href="/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/">saw in my retrocomputing projects</a>: where there&rsquo;s a reference and an oracle, AI flies; where there isn&rsquo;t, it spins in brute force.</p>
<p><strong>The target doesn&rsquo;t move.</strong> Nobody is going to update 1998&rsquo;s Zelda.</p>
<p><strong>And the legal side was settled thirty years ago.</strong> Sega v. Accolade and Sony v. Connectix drew the outline. The ports require you to supply your own ROM.</p>
<h3>A modern console is a PC<span class="hx:absolute hx:-mt-20" id="a-modern-console-is-a-pc"></span>
    <a href="#a-modern-console-is-a-pc" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The second half of the explosion, the PS4, PS5, Xbox One and Switch ports, has another explanation: those consoles are PCs or phones in a different case. The <a href="https://www.playstation.com/en-us/ps4/tech-specs/"target="_blank" rel="noopener">PS4</a> uses an AMD Jaguar x86-64, the <a href="https://blog.playstation.com/2020/03/18/unveiling-new-details-of-playstation-5-hardware-technical-specs/"target="_blank" rel="noopener">PS5</a> a Zen 2, the <a href="https://news.xbox.com/en-us/2020/03/16/xbox-series-x-tech/"target="_blank" rel="noopener">Xbox Series</a> another Zen 2, the Switch an NVIDIA <a href="https://www.techinsights.com/blog/nintendo-switch-teardown"target="_blank" rel="noopener">Tegra X1</a> ARM chip. Your PC&rsquo;s processor runs that code natively. So nobody needs to emulate the CPU.</p>
<p>The remaining work is translating the operating system and the GPU. <a href="https://github.com/shadps4-emu/shadPS4"target="_blank" rel="noopener">shadPS4</a> reimplements the PS4&rsquo;s system libraries and recompiles the shaders: games ship from the factory with AMD GPU machine code, which the emulator decodes instruction by instruction and converts to SPIR-V, Vulkan&rsquo;s format.</p>
<p><a href="https://almost-there-games.itch.io/azimuth"target="_blank" rel="noopener">Azimuth</a>, which makes Forza Horizon 2 run on Windows, translates Xbox WinRT calls to Win32 and DirectX 11.X to desktop DirectX 12, with the game&rsquo;s x86 code running directly. AnyPS5 relinks the executable: it takes the PS5 binary and produces a native Linux or Windows binary, linked against reimplemented system libraries. In all three cases, Proton, DXVK, VKD3D and MoltenVK had solved the graphics translation layer years earlier.</p>
<p>The reverse proof is the consoles that weren&rsquo;t PCs. The PS3 uses the Cell, a PowerPC with seven active coprocessors (the SPEs), each with its own local memory and no cache, and RPCS3 has been at it <a href="https://rpcs3.net/about"target="_blank" rel="noopener">since 2011</a>, with SPU emulation still the bottleneck today. The Xbox 360 is PowerPC too, which is why Sonic Unleashed needed XenonRecomp to translate PowerPC into C++. Reverse engineering is case by case, and the architecture decides whether the case is easy.</p>
<h3>AI is in the loop, and there&rsquo;s already a fight<span class="hx:absolute hx:-mt-20" id="ai-is-in-the-loop-and-theres-already-a-fight"></span>
    <a href="#ai-is-in-the-loop-and-theres-already-a-fight" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>That the 2026 ports use AI, many of them say outright. The <a href="https://github.com/SlickAmogus/silent-hill-decomp"target="_blank" rel="noopener">Silent Hill decomp</a> writes in its README that development is &ldquo;heavily AI-assisted (Claude Opus 4.6, 4.7 and the newer Fable model), and we&rsquo;re open about that. It is not automated translation of the game&rdquo;. The Pokémon Stadium recomp <a href="https://retrododo.com/a-pokemon-stadium-recomp-has-finally-arrived-but-lists-claude-as-a-contributor/"target="_blank" rel="noopener">lists Claude as a contributor</a>.</p>
<p>The devs of the Zelda and Banjo recomps, who spent years doing this by hand, <a href="https://kotaku.com/zelda-and-banjo-recompiled-devs-go-to-war-with-ai-vibe-coded-slopcomps-2000739936"target="_blank" rel="noopener">went to war</a> with what they call &ldquo;slopcomps&rdquo;, agent-generated ports of alpha quality.</p>
<p>And it&rsquo;s worth separating headline from actual state here too. AnyPS5 has a 0.1 version from September that, according to those who tested it, runs one 2D indie game; the viral claim that &ldquo;the PS5 is 80% ported to PC&rdquo; comes from fans, and no 3D game runs. Astro Bot runs, but in emulators (KytyPS5, SharpEmu), which take the traditional path. Forza Horizon 2 runs, and Azimuth is a closed binary from a studio that declares itself &ldquo;AI assisted&rdquo; without saying anything more.</p>
<h2>&ldquo;But in two years tokens will cost nothing&rdquo;<span class="hx:absolute hx:-mt-20" id="but-in-two-years-tokens-will-cost-nothing"></span>
    <a href="#but-in-two-years-tokens-will-cost-nothing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The standard answer to all of this is: it&rsquo;s hard today, in two years it&rsquo;s trivial, because AI grows exponentially. The numbers say otherwise.</p>
<p>The price of the most expensive tier barely fell. GPT-4 in March 2023 cost US$ 30 and 60 per million input and output tokens; Claude 3 Opus in 2024, 15 and 75; today&rsquo;s frontier models, Fable 5.1 and GPT-6 Astra, <a href="https://claude.com/pricing"target="_blank" rel="noopener">cost</a> <a href="https://developers.openai.com/api/docs/pricing"target="_blank" rel="noopener">10 and 50</a>. In three and a half years, the frontier got between 1.2 and 3 times cheaper, depending on which end you look at.</p>
<p>What really fell was the cost of a fixed quality: Epoch AI measured drops <a href="https://epoch.ai/blog/llm-inference-price-trends"target="_blank" rel="noopener">of 9 to 900 times per year</a> depending on the task, and in a <a href="https://epoch.ai/gradient-updates/how-persistent-is-the-inference-cost-burden"target="_blank" rel="noopener">2026 review</a> sums it up as &ldquo;very roughly 5 to 10 times per year&rdquo;, with the caveat that it might slow down. That&rsquo;s real and it&rsquo;s great.</p>
<p>But apply the math to Bun. US$ 165K divided by 10 is US$ 16K. By 100, US$ 1,650. That&rsquo;s to port a runtime with the source, the tests and the author in hand.</p>
<p>For an amateur trying to clone Photoshop with none of that, the bill starts orders of magnitude higher and falls in the same proportion. Cheap isn&rsquo;t the same as trivial.</p>
<p>And the &ldquo;exponential&rdquo; premise died in 2024. Ilya Sutskever said at NeurIPS that <a href="https://www.globalbankingandfinance.com/ai-with-reasoning-power-will-be-less-predictable-ilya-sutskever-says/"target="_blank" rel="noopener">pre-training as we know it will end</a>, because there&rsquo;s only one internet. Epoch projects that reasoning model scaling <a href="https://epoch.ai/gradient-updates/how-far-can-reasoning-models-scale"target="_blank" rel="noopener">converges to the general frontier rate</a> in about a year.</p>
<p>I&rsquo;ve written about this three times in recent weeks: <a href="/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/">the limits</a> of what the model reproduces, <a href="/en/2026/10/12/llms-agents-competent-enough/">the convergence</a> of raw models with the gains coming from the harness, and <a href="/en/2026/10/11/are-there-better-languages-for-programming-with-llms/">the languages benchmark</a> where the frontier models tied at the ceiling. The tool we have is the tool we&rsquo;ll have for a good while, with incremental improvement. Plan with it.</p>
<p>Worth recalling the number that opens the limits post: per the <a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/"target="_blank" rel="noopener">Octoverse 2025</a>, GitHub&rsquo;s official report, 81.5% of contributions on the platform happened in private repositories. That&rsquo;s the code that really matters, the code that pays salaries, and no LLM has seen a line of it. The model reproduces what was in the training data, and that code was never there.</p>
<p>Now extend that to every SaaS product and every component it uses. The Adobe code that&rsquo;s actually worth something, the color engine, the profiles, the cloud filters, isn&rsquo;t available anywhere, not even as a binary. Anyone who wants to reproduce it will have to redo the research and development, expensive and slow, over the same years Adobe took. And at the end they still run into third-party licensed intellectual property, Pantone, camera SDKs, manufacturer profiles, that you will never be able to have.</p>
<h2>Answering the list from the top<span class="hx:absolute hx:-mt-20" id="answering-the-list-from-the-top"></span>
    <a href="#answering-the-list-from-the-top" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Does PhotoCraft exist?</strong> It does, it&rsquo;s a two-week-old alpha with more than 800 open issues, rudimentary color management, freezing above 8K and opening PSDs wrong. It looks like Photoshop in a screenshot. It can improve a lot, and it will discover that the target moves and that Photoshop&rsquo;s expensive parts live in the cloud or in manufacturer contracts.</p>
<p><strong>Does REA exist?</strong> It does, it&rsquo;s good, and it&rsquo;s a toolbox for people who already know how to use Ghidra, requiring the binary in hand, the tools installed and hundreds of thousands of tokens per analysis. The project itself avoids saying it clones programs.</p>
<p><strong>Did recomps and decomps accelerate?</strong> Yes, for real, and AI has a part in it. They accelerated where the binary exists, is small, has been documented for 25 years and doesn&rsquo;t move. Or where the console is a PC in disguise and the work is API translation, solved by Wine and Vulkan years earlier.</p>
<p><strong>Is Adobe dead?</strong> Adobe has around 40 million subscribers by the most cited estimate, the features that sell subscriptions run on its servers, and thirty years of GIMP still leave the print shop asking for Photoshop. I wish it were otherwise. The data says what will happen is what always happened with clones of a live product: years of chasing, and when you catch up, the value has already moved.</p>
<p><strong>Are programmers dead?</strong> Rewriting Bun required Bun&rsquo;s author. The decomps that work have people who know the hardware driving the agent, and the ones that don&rsquo;t became &ldquo;slopcomps&rdquo;, name and all. Reverse engineering got cheaper and more accessible, as it did with Ghidra in 2019, and it&rsquo;s still an engineer&rsquo;s job. Without us, the tool returns a pretty screenshot.</p>
<p>Proprietary software with a binary in hand will come under pressure, and it should. Most of the software you use has no binary at all, and the software that does already depends on cloud services that don&rsquo;t disassemble. Software engineering with AI has a great road ahead. &ldquo;It&rsquo;s over&rdquo; headlines get clicks and don&rsquo;t compile.</p>
]]></content:encoded><category>artificial-intelligence</category><category>vibe-coding</category><category>retrocomputing</category><category>open-source</category></item><item><title>Codes of Conduct Are the Root of All Evil: Reclaiming Your Freedom</title><link>https://akitaonrails.github.io/en/2026/09/14/codes-of-conduct-root-of-all-evil/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/09/14/codes-of-conduct-root-of-all-evil/</guid><pubDate>Mon, 14 Sep 2026 17:00:00 -0300</pubDate><description>&lt;p&gt;Every major open source project today ships with a &lt;code&gt;CODE_OF_CONDUCT.md&lt;/code&gt; in the repository. The idea was sold that this existed to &amp;ldquo;protect minorities&amp;rdquo; and &amp;ldquo;create safe spaces.&amp;rdquo; In practice, what I watched happen over the last decade was something else: an instrument to cancel, persecute, and ban anyone who thought differently from whoever was in control. And the people leading those hunts, as a rule, were not the ones maintaining the projects&amp;rsquo; code.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Every major open source project today ships with a <code>CODE_OF_CONDUCT.md</code> in the repository. The idea was sold that this existed to &ldquo;protect minorities&rdquo; and &ldquo;create safe spaces.&rdquo; In practice, what I watched happen over the last decade was something else: an instrument to cancel, persecute, and ban anyone who thought differently from whoever was in control. And the people leading those hunts, as a rule, were not the ones maintaining the projects&rsquo; code.</p>
<p>This is my thesis, and I know it&rsquo;s unpopular. It took me ten years of patience to be able to write this piece. I stayed quiet watching this theater repeat itself year after year, waiting for the right moment to document everything I witnessed up close, and today I get to watch, with real pleasure, my own predictions come true one by one.</p>
<p>And before some smart aleck tries this one: I know boycotts, doxxing, and witch hunts exist with no CODE_OF_CONDUCT.md whatsoever, they always have. The title takes aim at what this file turned into: the instrument that took an internet-mob tactic and stamped it as official project policy, with a committee, a process, and a veneer of institutional legitimacy. A 500-line markdown file scares nobody by itself; what it became does.</p>
<blockquote>
  <p>Easy money was the fuel. The code of conduct was the weapon these people built to formalize what used to be just a shout in the street.</p>

</blockquote>
<p>One question is where the energy came from; another is the instrument it adopted to turn into permanent power inside the project. Keep that distinction in mind, because it holds up the whole piece. But before getting to the philosophy, let me tell the economic part, because without understanding the money you won&rsquo;t understand the rest.</p>
<h2>The bubble that funded all of this<span class="hx:absolute hx:-mt-20" id="the-bubble-that-funded-all-of-this"></span>
    <a href="#the-bubble-that-funded-all-of-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>From roughly 2012 to 2022, the tech industry lived through the biggest hiring bubble in history. Zero interest rates, infinite capital, and big tech companies growing like there was no tomorrow. We reached the surreal point of companies hiring engineers with no work for them to do. Keith Rabois, of the PayPal mafia, publicly accused Google and Meta of hiring thousands of people to do <a href="https://fortune.com/2023/03/10/google-over-hired-talent-do-nothing-fake-work-stop-working-rivals-former-paypal-boss-keith-rabois/"target="_blank" rel="noopener">&ldquo;fake work&rdquo;, out of vanity, and so they wouldn&rsquo;t go work for competitors</a>. A former Meta employee, laid off in the first 2022 wave, put it better: <a href="https://www.businesstoday.in/technology/news/story/paid-employees-to-do-fake-work-laid-off-worker-accuses-meta-of-not-having-enough-work-for-staff-373423-2023-03-15"target="_blank" rel="noopener">&ldquo;they were hoarding us like Pokémon cards&rdquo;</a>. The <a href="https://www.ibtimes.co.uk/how-get-paid-doing-nothing-inside-silicon-valleys-controversial-rest-vest-culture-1633884"target="_blank" rel="noopener">&ldquo;rest and vest&rdquo;</a> culture, collecting salary and stock options while doing almost nothing, had already been documented back in 2017.</p>
<p>It was this bubble that funded the &ldquo;coding is the profession of the future&rdquo; wave. Bootcamps <a href="https://www.coursereport.com/reports/2020-coding-bootcamp-market-size-study"target="_blank" rel="noopener">went from 2,178 graduates in 2013 to nearly 25,000 in 2020</a> in the US and Canada alone, growth of more than a thousand percent. <a href="https://www.theverge.com/2012/1/6/2688172/mayor-bloomberg-resolves-to-take-a-coding-class-in-2012"target="_blank" rel="noopener">Bloomberg resolved to learn to code as a New Year&rsquo;s resolution in 2012</a>. <a href="https://www.wired.com/2014/12/obama-becomes-first-president-write-computer-program/"target="_blank" rel="noopener">Obama wrote a line of code on TV in 2014</a>.</p>
<p>I told this story in more detail in a February 2020 video, back when the bubble was still inflating (<a href="/2020/02/19/akitando-72-rant-programacao-nao-e-facil/">transcript here</a>):</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/V7oUDL7E1g4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Tech influencer became a profession. Everyone was going to be a programmer.</p>
<p>Then the bubble popped. <a href="https://techcrunch.com/2024/05/01/a-comprehensive-archive-of-2023-tech-layoffs/"target="_blank" rel="noopener">2022: nearly 165,000 laid off. 2023: more than 262,000</a>, according to Layoffs.fyi. Meta cut <a href="https://about.fb.com/news/2022/11/mark-zuckerberg-layoff-message-to-employees/"target="_blank" rel="noopener">11,000 in November 2022</a> with Zuckerberg admitting <em>&ldquo;I got this wrong&rdquo;</em>, and another <a href="https://fortune.com/2023/03/14/meta-layoffs-10000-mark-zuckerberg-year-of-efficiency-hiring-freeze"target="_blank" rel="noopener">10,000 in the &ldquo;year of efficiency&rdquo;</a> in 2023. Amazon cut <a href="https://cbsaustin.com/news/nation-world/amazon-cuts-9000-jobs-now-at-least-27000-layoffs-in-2023"target="_blank" rel="noopener">27,000</a>. Google, <a href="https://blog.google/company-news/inside-google/message-ceo/january-update/"target="_blank" rel="noopener">12,000</a>, with Pichai admitting that <em>&ldquo;we hired for a different economic reality than the one we face today&rdquo;</em>. Stripe was the most honest: <a href="https://ca.finance.yahoo.com/news/digital-payments-firm-stripe-lay-134215274.html"target="_blank" rel="noopener">&ldquo;we overhired&rdquo;</a>.</p>
<p>I recorded that burst in the heat of the moment, in a November 2022 video (<a href="/2022/11/22/akitando-132-rant-a-bolha-de-startups-estourou/">transcript here</a>):</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/xxoVJQvEyEU"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>And because the timing writes its own joke, on November 30, 2022, right in the middle of the bloodbath, ChatGPT came out. <a href="https://www.reuters.com/technology/chatgpt-sets-record-fastest-growing-user-base-analyst-note-2023-02-01/"target="_blank" rel="noopener">A hundred million users in two months</a>, the fastest-growing app ever seen up to that point, according to a UBS estimate. The headlines turned into an ACM talk called <a href="https://learning.acm.org/techtalks/endporgramming"target="_blank" rel="noopener">&ldquo;Large Language Models and the End of Programming&rdquo;</a>, <a href="https://www.techspot.com/news/102020-nvidia-boss-jensen-huang-children-shouldnt-learn-code.html"target="_blank" rel="noopener">Jensen Huang saying no child needs to learn to code anymore</a>, <a href="https://www.cognition.ai/blog/introducing-devin"target="_blank" rel="noopener">Devin announcing itself as the first AI software engineer</a>, <a href="https://daringfireball.net/linked/2025/08/20/claim-chowder-amodei"target="_blank" rel="noopener">Dario Amodei promising AI would write 90% of code within three to six months</a>. Spoiler: it didn&rsquo;t.</p>
<p>Why does this story matter? Because it was exactly during this decade of easy money that open source got colonized. When there&rsquo;s money to spare and a shortage of real work, there&rsquo;s time and people to spare for playing politics inside projects. And that&rsquo;s what happened.</p>
<h2>The decade of the witch hunt<span class="hx:absolute hx:-mt-20" id="the-decade-of-the-witch-hunt"></span>
    <a href="#the-decade-of-the-witch-hunt" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The central artifact of this story is the <a href="https://ethicalsource.dev/blog/contributor-covenant-stewardship/"target="_blank" rel="noopener">Contributor Covenant</a>, created in 2014 by Coraline Ada Ehmke and adopted by thousands of projects, including practically every giant in the industry: CNCF, Apple, Google, Microsoft, Linux. The author herself, on the day Linux adopted her code, tweeted in no uncertain terms: <a href="https://itsfoss.com/linux-code-of-conduct/"target="_blank" rel="noopener"><em>&ldquo;Some people are saying that the Contributor Covenant is a political document, and they&rsquo;re right&rdquo;</em></a>. When the document&rsquo;s own author admits it&rsquo;s political, the debate over &ldquo;safe space&rdquo; is over before it starts.</p>
<p>The list of victims from this era is long, so let&rsquo;s get to the main ones.</p>
<p>First, it&rsquo;s worth noting how far this crowd&rsquo;s reach went. Coraline worked at GitHub between 2016 and 2017, until she was let go (her version of events is in the piece <a href="https://where.coraline.codes/writing/my-year-at-github/"target="_blank" rel="noopener">&ldquo;Antisocial Coding: My Year at GitHub&rdquo;</a>). And GitHub was the perfect target: it&rsquo;s where practically all the world&rsquo;s open source lived. It was in this era that the original founders left the picture. Tom Preston-Werner <a href="https://www.sj-r.com/story/news/2014/05/10/github-women-miss-founder-who/37382118007/"target="_blank" rel="noopener">resigned in 2014</a> amid the Julie Ann Horvath harassment scandal, even though the internal investigation concluded there was nothing illegal, only &ldquo;errors in judgment.&rdquo; Chris Wanstrath had already announced he&rsquo;d step down as CEO in 2017 and, after the sale to Microsoft in 2018, stayed on a few more years as a technical fellow before leaving for good. Today none of the original founders work there.</p>
<p>Her legacy outlived the firing. The Contributor Covenant became one of the <a href="https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-code-of-conduct-to-your-project"target="_blank" rel="noopener">templates GitHub makes easy to adopt</a> when you create a repository&rsquo;s <code>CODE_OF_CONDUCT.md</code>. And in 2020 came the crown jewel: in the middle of the George Floyd protests, GitHub announced it was retiring the name <code>master</code>, and since <a href="https://github.blog/changelog/2020-10-01-the-default-branch-for-newly-created-repositories-is-now-main/"target="_blank" rel="noopener">October 1, 2020 every new repository is born <code>main</code></a>.</p>
<p>The debate was stupid from the start. Git never had a <code>slave</code> branch. Petr Baudis, who named it in the original scripts, <a href="https://x.com/xpasky/status/1271477451756056577"target="_blank" rel="noopener">explained on X that <code>master</code> there came from &ldquo;master copy&rdquo;</a>, like the master recording of an album (Baudis himself later said he now prefers <code>main</code>; the etymology hasn&rsquo;t changed). Not even that detail held back the change: even the <a href="https://sfconservancy.org/news/2020/jun/23/gitbranchname/"target="_blank" rel="noopener">Software Freedom Conservancy publicly endorsed</a> the switch, and anyone with automation assuming <code>master</code> had to scramble to catch up. Nobody got any more protected because of this change, but it&rsquo;s there, in every programmer&rsquo;s workflow, every single day.</p>
<p><strong>Brendan Eich, 2014.</strong> The guy invented JavaScript, co-founded Mozilla, was CTO since 2005. He became CEO and lasted <a href="https://abcnews.go.com/Business/mozilla-ceo-resigns-calif-gay-marriage-ban-campaign/story?id=23181711"target="_blank" rel="noopener">eleven days in the job</a>. The crime: a thousand-dollar donation in 2008 to California&rsquo;s Proposition 8. Employees tweeted calling for his head, <a href="https://en.wikipedia.org/wiki/Brendan_Eich"target="_blank" rel="noopener">OkCupid blocked Firefox users with a protest message</a>, and he fell. Andrew Sullivan, gay and one of the first prominent advocates for same-sex marriage, wrote at the time <a href="https://dish.andrewsullivan.com/2014/04/03/the-hounding-of-brendan-eich/"target="_blank" rel="noopener">&ldquo;The Hounding of a Heretic&rdquo;</a>: when careers depend on an ideological purity test, the witch hunt has already won. And notice: there was no code of conduct involved here at all, it was pure boycott pressure. The method already existed before the document; the document only made it official.</p>
<p><strong>Larry Garfield, 2017.</strong> Twelve years contributing to Drupal. When it leaked that he took part in a BDSM subculture, on a private site, outside the project, Drupal&rsquo;s conduct committee investigated and concluded: <a href="https://www.drupal.org/association/blog/a-statement-from-the-executive-director"target="_blank" rel="noopener">no code of conduct violation</a>. Dries Buytaert went over the committee&rsquo;s own head and <a href="https://dri.es/living-our-values"target="_blank" rel="noopener">expelled him anyway</a>, because &ldquo;association with his belief system&rdquo; was incompatible with the project&rsquo;s goals. TechCrunch summed it up the same way: <a href="https://techcrunch.com/2017/03/26/sex-and-gor-and-open-source/"target="_blank" rel="noopener">punished for something said outside the project</a>. Eighty-five developers <a href="https://www.inc.com/sonya-mann/drupal-confessions-open-letter.html"target="_blank" rel="noopener">signed an open letter</a> threatening to leave. It didn&rsquo;t help. And notice the detail that buries the &ldquo;safe space&rdquo; thesis: the code of conduct process worked and cleared the guy. When the mob pushed, the paper held nothing; the person at the top decided, like it always was.</p>
<p><strong>Node.js, 2017.</strong> The 13-person TSC voted on expelling Rod Vagg for, among other things, having tweeted an article questioning the side effects of codes of conduct. Reading criticism of a code of conduct almost became a code of conduct violation: <a href="https://www.theregister.com/2017/08/24/nodejs_forks_ayo_code_of_conduct/"target="_blank" rel="noopener">the vote was 6 to 4 against expulsion</a>, by a narrow margin. The machine lost that round, but the message had already gotten out: four of the people who wanted Vagg&rsquo;s head resigned from the committee that same day, and the project got a fork called Ayo.js hours later. Losing the vote didn&rsquo;t stop the damage.</p>
<p><strong>Linus Torvalds, 2018.</strong> In September, according to reporting at the time, the New Yorker had sent him questions about his abusive behavior in emails. That same weekend, Linus <a href="https://www.newyorker.com/science/elements/after-years-of-abusive-e-mails-the-creator-of-linux-steps-aside"target="_blank" rel="noopener">apologized and announced he&rsquo;d take some time off to &ldquo;understand people&rsquo;s emotions&rdquo;</a> and the kernel <a href="https://itsfoss.com/linux-code-of-conduct/"target="_blank" rel="noopener">swapped the Code of Conflict for the Contributor Covenant</a>. Linus has been blunt in emails forever, everyone knows that, and he came back a month later. But the message was sent: if not even the guy who created the kernel was safe, nobody was.</p>
<p><strong>Richard Stallman, 2019.</strong> The creator of the GPL, founder of the FSF, the embodiment of free software. An MIT mailing list thread leaked in which he discussed the legal semantics of the Minsky/Epstein case. Vice ran headlines saying he had <a href="https://news.tuxmachines.org/node/128122"target="_blank" rel="noopener">&ldquo;defended Epstein&rdquo; and called the victims &ldquo;entirely willing&rdquo;</a>, a reading the email thread itself doesn&rsquo;t support: he was questioning the legal terminology of the accusation against Minsky. The <a href="https://medium.com/@selamie/remove-richard-stallman-fec6ec210794"target="_blank" rel="noopener">&ldquo;Remove Richard Stallman&rdquo;</a> campaign exploded, and within days he <a href="https://www.npr.org/2019/09/17/761718975/free-software-pioneer-quits-mit-over-his-comments-on-epstein-sex-trafficking-cas"target="_blank" rel="noopener">resigned from MIT and the FSF presidency</a>. When he returned to the FSF board in 2021, <a href="https://rms-open-letter.github.io/"target="_blank" rel="noopener">an open letter with more than 3,000 signatures and dozens of organizations</a> came out demanding his head and the whole board&rsquo;s. Red Hat <a href="https://www.redhat.com/en/blog/red-hat-statement-about-richard-stallmans-return-fsf-board"target="_blank" rel="noopener">cut funding to the FSF</a>. <a href="https://rms-support-letter.github.io/"target="_blank" rel="noopener">A support letter gathered nearly 7,000 signatures</a> and, delicious detail, Debian voted on a resolution about the case and <a href="https://www.debian.org/vote/2021/vote_002"target="_blank" rel="noopener">the winning option was to say nothing</a>. Even faking neutrality took a vote.</p>
<p>And there&rsquo;s the most recent case, and maybe the most instructive one: <strong>Tim Peters, 2024</strong>. A Python legend, three decades of contribution, suspended for three months by the PSF&rsquo;s conduct committee <a href="https://www.theregister.com/software/2024/08/09/core-python-developer-suspended-for-three-months/1429020"target="_blank" rel="noopener">over vague accusations of creating an &ldquo;atmosphere of FUD&rdquo;</a>, in a fight over the foundation&rsquo;s bylaws and the committee&rsquo;s own methods. The community reacted badly, but there was no reversing it: he served the three months and only came back once the suspension expired, in November. The pattern held: disagreeing with moderation became a punishable offense.</p>
<p><strong>DHH, 2021.</strong> I saved this one for last because it&rsquo;s the case that changes the story. And note: this wasn&rsquo;t even open source, it was his own company. The same mechanism, now inside the office. In April 2021, at the height of the BLM era, an internal DEI committee inside Basecamp, the company of Ruby on Rails&rsquo; creator and Jason Fried, dug up an old &ldquo;funny customer names&rdquo; list that had been circulating internally. The discussion escalated until an employee invoked the &ldquo;pyramid of hate&rdquo; and argued that list was the foundation of racial violence and even genocide. The founders&rsquo; response was to shut down the topic, dissolve the committee, and <a href="https://world.hey.com/dhh/basecamp-s-new-etiquette-regarding-societal-politics-at-work-b44bef69"target="_blank" rel="noopener">ban political and societal discussion on internal channels</a>. The internet exploded. At the next all-hands, there were <a href="https://www.theverge.com/2021/5/3/22418208/basecamp-all-hands-meeting-employee-resignations-buyouts-implosion"target="_blank" rel="noopener">two and a half hours of people crying and yelling on Zoom</a>. Ryan Singer, eighteen years at the company, said there that he didn&rsquo;t accept the &ldquo;white supremacy culture&rdquo; label being applied to the company. He was suspended half an hour after the meeting and resigned that weekend. In the end, <a href="https://www.nytimes.com/2021/04/30/technology/basecamp-politics-ban-resignations.html"target="_blank" rel="noopener">a third of the company, twenty of the 57 employees, left with a voluntary severance package</a>.</p>
<p>And this is where this case splits off from all the others: he didn&rsquo;t bend. No public humiliation ritual, no apology, no walking it back. He preferred to lose a third of the company over handing over control of it. Basecamp survived, went back to being 37signals, and DHH learned right there, firsthand, what kind of people he was dealing with. Hold on to that name, because it comes back.</p>
<p>Someone&rsquo;s going to point out that his rule is also a written document banning a topic. Yes, and the difference is exactly the point: DHH&rsquo;s rule bans an entire subject, the same for everyone, no matter which side. A code of conduct bans a person and an opinion, selectively, depending on who&rsquo;s in power that month.</p>
<blockquote>
  <p>One locks the topic at the door. The other opens a courtroom inside.</p>

</blockquote>
<p>Notice the pattern. In none of these cases was the problem code. In none of them did anyone commit a bug, steal code, sabotage a release. The offenses were opinions, political donations, private life, semantics on a mailing list. The technical criterion got replaced by a political one, and the code of conduct was the legal instrument of that swap. These are famous cases, not statistics. But when the list includes the creators of JavaScript, the GPL, and Linux, the sample doesn&rsquo;t need to be big to make the point.</p>
<h2>And the results?<span class="hx:absolute hx:-mt-20" id="and-the-results"></span>
    <a href="#and-the-results" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Ten years of the code-of-conduct era should have left behind a trail of good numbers. If the justification was protecting minorities and making open source more diverse and less toxic, where&rsquo;s the improvement? I went looking for the serious research on the subject. What exists tells an interesting story.</p>
<p>On adoption: <a href="https://www.win.tue.nl/~aserebre/SANER2017.pdf"target="_blank" rel="noopener">Tourani, Adams, and Serebrenik measured in 2017</a> that around 35% of GitHub&rsquo;s 150 most popular projects had a code of conduct. And that enforcement was rare: the creators of these codes, in a sample of four interviewees, talked about single-digit case counts over years. A <a href="https://par.nsf.gov/servlets/purl/10347026"target="_blank" rel="noopener">2021 CSCW study</a> looked at 52,000 repositories: 12.6% had a CoC, and only 10% of the conversations mentioning the code were real moderation use of it. Most adoptions happened with no visible public discussion in the repo. The same paper states, in plain words, that there is no empirical evidence that a code of conduct attracts new contributors.</p>
<p>On attracting people, by the way, <a href="https://cmustrudel.github.io/papers/cscw19signals.pdf"target="_blank" rel="noopener">Qiu et al. measured what actually makes someone join a project</a>: a good README, star count, recent activity, an issue template. A code of conduct didn&rsquo;t even make it in as a variable in their model, and note that they did test maintainer responsiveness, which also came back not significant. The study that specifically measured where a CoC ranks among the factors was a separate one, <a href="https://link.springer.com/chapter/10.1007/978-3-030-20883-7_9"target="_blank" rel="noopener">Fronchetti, Wiese, Pinto, and Steinmacher, also from 2019</a>: a CoC ranked among the worst-placed factors for attracting new contributors. Nobody picks a project because of its code of conduct.</p>
<p>On diversity, which was the original promise, there is a specific study, and the answer is no. <a href="https://dl.acm.org/doi/10.1145/3236024.3275441"target="_blank" rel="noopener">Robson, at ESEC/FSE 2018</a>, looked at GitHub&rsquo;s 500 most popular projects: projects that adopted a CoC saw women&rsquo;s participation grow at practically the same rate as those that didn&rsquo;t (roughly a 1.44% increase versus 1.43%, per the later survey that cites the study). No statistical difference to back up the promise. <a href="https://research.tue.nl/files/198367174/Enache_B.pdf"target="_blank" rel="noopener">Enache, in a 2017 master&rsquo;s thesis for TU Eindhoven, covering 149 open source communities</a>, reached the same conclusion: no significant result showing a CoC changes women&rsquo;s participation.</p>
<p>And there&rsquo;s a new, heavyweight piece of research, published now in 2026 at ICSE, the field&rsquo;s most important conference: <a href="https://jys-sun.github.io/website/resources/Beyond_Adoption_ICSE2026_CR.pdf"target="_blank" rel="noopener">Sun et al. ran a genuine causal experiment</a>, comparing 4,684 pairs of repositories that adopted a CoC against matched pairs that didn&rsquo;t. The result cuts both ways. Adopting a CoC does attract more new contributors, and that effect grows over time. Except adopting a CoC also increases the number of existing contributors who disengage, an effect concentrated specifically in the first one to three months after adoption. In other words: the most recent and most rigorous study that exists shows, with numbers, the exact pattern this piece has been documenting case by case the whole time. Adopting the document doesn&rsquo;t build a new community, it pushes out the people who were already there.</p>
<p>GitHub&rsquo;s 2017 survey already showed <a href="https://opensourcesurvey.org/2017/"target="_blank" rel="noopener">95% men and 3% women in open source</a>. The best long-term data that exists, from <a href="https://arxiv.org/html/2202.07278v1"target="_blank" rel="noopener">Rossi and Zacchiroli at ICSE 2022</a>, analyzed 2.2 billion commits from the Software Heritage archive. Gender was detectable for 64% of authors, and within that group, women are 13.5% of authors and sign 8.1% of commits. Their participation had been growing slowly and steadily for twelve years, and dropped during the pandemic. The paper doesn&rsquo;t discuss codes of conduct, so what follows is my own reading, not the study&rsquo;s: a curve that climbs the same way the whole decade, with no visible step up when the Contributor Covenant spread, is the opposite of evidence that the document made a difference.</p>
<p>On toxicity, the <a href="https://courtney-e-miller.github.io/papers/DidYouMissMyCommentOrWhat.pdf"target="_blank" rel="noopener">ICSE 2022 study</a> finds, in a footnote and by extrapolation, something close to 1.3 toxic comments per thousand on GitHub. Nobody has a historical series comparing before and after the CoC era. There simply is no baseline to say whether things got worse or better.</p>
<p>The only randomized experiment that would actually support the case for rules <a href="https://doi.org/10.1073/pnas.1813486116"target="_blank" rel="noopener">is Matias&rsquo;s, published in PNAS in 2019</a>: rule reminders actively displayed on a randomly-sampled set of r/science threads increased newcomer participation by 70%. Except the experiment is on Reddit, with the rule pinned right in front of whoever walked into that specific thread. A static file forgotten in a repository, that nobody reads after adoption day, doesn&rsquo;t come close to that. The very research that shows a rule working is proof that the problem was never whether the file exists or not. It&rsquo;s that nobody enforces it, nobody displays it, nobody makes it stick.</p>
<p>To sum up: a whole decade of codes of conduct, and the original promise remains exactly that, a promise. What got documented was adoption without discussion, rare enforcement, and, at best, a whole lot of political process.</p>
<blockquote>
  <p>As protection, it&rsquo;s almost never invoked. As a political weapon, it only needs to be invoked once, against the right person.</p>

</blockquote>
<h2>The pushback came from where nobody expected<span class="hx:absolute hx:-mt-20" id="the-pushback-came-from-where-nobody-expected"></span>
    <a href="#the-pushback-came-from-where-nobody-expected" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Easy money ran out in 2022, and with it, the industry&rsquo;s patience for this theater. And leading the pushback was the guy who had already refused to bend back in 2021: DHH, an old-guard ex-Mac fanboy.</p>
<p>DHH has been writing against this wave for a while now: <a href="https://world.hey.com/dhh/the-waning-days-of-dei-s-dominance-9a5b656c"target="_blank" rel="noopener">&ldquo;The waning days of DEI&rsquo;s dominance&rdquo;</a> in 2022, <a href="https://world.hey.com/dhh/dei-is-done-minus-the-mop-up-b3bbbb64"target="_blank" rel="noopener">&ldquo;DEI is done&rdquo;</a> in 2024. In 2022 Ruby Central <a href="https://world.hey.com/dhh/no-railsconf-faa7935e"target="_blank" rel="noopener">pulled him from the RailsConf keynote</a>, the conference for the framework he himself created, saying it wanted to <em>&ldquo;share the opening stage with other contributors&rdquo;</em>. The following year Rails World was born, the official Rails Foundation conference, and DHH became its keynote speaker. In 2024 he launched Omakub, and in June 2025, <a href="https://world.hey.com/dhh/omarchy-is-out-4666dd31"target="_blank" rel="noopener">Omarchy</a>: Arch Linux with Hyprland and a bunch of opinionated scripts on top, which had passed 40,000 stars on GitHub by September 2026 and became 37signals&rsquo; default environment for anyone touching infra and Ruby.</p>
<p>Then the cancel machine switched on again. In September 2025 he published <a href="https://world.hey.com/dhh/as-i-remember-london-e7d38e64"target="_blank" rel="noopener">&ldquo;As I remember London&rdquo;</a>, and the reaction was the usual script: a petition to remove him, accusations, an attempted boycott. His response was <a href="https://world.hey.com/dhh/we-ve-all-had-enough-of-this-nonsense-8545dd26"target="_blank" rel="noopener">&ldquo;We&rsquo;ve all had enough of this nonsense&rdquo;</a>: <em>&ldquo;every few years, the same sad little clique of Ruby malcontents tries to cancel me from Rails&rdquo;</em>.</p>
<p>A month later, in October 2025, it was Framework&rsquo;s turn, the laptop maker: <a href="https://www.theregister.com/software/2025/10/14/framework-flame-war-erupts-over-linux-controversy/1466815"target="_blank" rel="noopener">a thread with more than 1,500 replies on the company&rsquo;s own forum</a>, opened by a Debian developer calling the Hyprland community, which Framework sponsored, &ldquo;toxic and hateful,&rdquo; and threatening a boycott because the company also promoted Omarchy on social media. The Framework CEO&rsquo;s response is the line this whole decade had been missing:</p>
<blockquote>
  <p><em>&ldquo;We deliberately created a big tent, because we want open source to win. We don&rsquo;t partner based on the beliefs of individuals or organizations.&rdquo;</em></p>

</blockquote>
<p>And the machine didn&rsquo;t just come after him. Ruby Central, the same organization that had disinvited DHH from the keynote in 2022, gave him a stage at RailsConf 2025. The retaliation came in money: according to developer Joel Drapper&rsquo;s reporting, Sidekiq <a href="https://mjtsai.com/blog/2025/09/"target="_blank" rel="noopener">pulled its $250,000-a-year sponsorship</a> because of it. Weeks later, in September 2025, Ruby Central <a href="https://lwn.net/Articles/1040778/"target="_blank" rel="noopener">stripped GitHub access from every longtime RubyGems and Bundler maintainer</a>, citing supply-chain security. Ellen Dash, who had maintained the project for ten years, quit, calling the move a &ldquo;hostile takeover,&rdquo; and Drapper&rsquo;s investigation points to pressure from Shopify, which had become practically the organization&rsquo;s only source of money. Ruby Central itself ended up publishing an <a href="https://www.theregister.com/2026/04/01/ruby_central_report/"target="_blank" rel="noopener">incident report</a> in April 2026, promising to &ldquo;strengthen governance.&rdquo; That&rsquo;s the whole pattern: when the machine can&rsquo;t take the target down, it burns the house down around them.</p>
<p>A GNOME developer published <a href="https://blogs.gnome.org/alatiera/2025/11/06/dhh-and-omarchy-midlife-crisis/"target="_blank" rel="noopener">a piece attacking Omarchy on GNOME&rsquo;s official blogs site</a>. And the result of all that fury? Nothing. In August 2026 the <a href="https://www.theregister.com/os-platforms/2026/08/27/omarchy-distro-gains-serious-backing/5293026"target="_blank" rel="noopener">Omacom Foundation</a> was born, with eight million dollars at launch: a million each from Tobi Lütke (Shopify), Patrick Collison (Stripe), Michael Dell, Jack Dorsey, Matthew Prince (Cloudflare), Brendan Iribe, Jason Fried, and DHH himself. The foundation became Hyprland&rsquo;s exclusive sponsor, with Vaxry working on it full-time. When 1Password came in as a sponsor, the <a href="https://www.alilleybrinker.com/blog/1password-funds-ethnic-cleansing/"target="_blank" rel="noopener">cancellation attempt</a> was immediate, and so was <a href="https://www.theverge.com/tech/988536/1password-dhh-linux-controversy"target="_blank" rel="noopener">the CEO&rsquo;s internal response</a>: <em>&ldquo;our donation is not an endorsement of personal opinions&rdquo;</em>. And the game goes on.</p>
<p>And I put my money where my mouth is: <a href="https://x.com/AkitaOnRails/status/2098792361291567488"target="_blank" rel="noopener">I made my donation to the foundation</a> precisely because of the patrol&rsquo;s whining. Nothing irritates that crowd more than watching a cancellation fail in real time.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260914175728_omacom-doacao.jpeg" alt="Recibo da minha doação de 2.048 dólares para a Omacom Foundation, assinado pelo DHH como Founder & President"  loading="lazy" /></p>
<p>This is the point: the machine still exists, but it lost its power. In 2014 it brought down a CEO in eleven days. In 2026 it can&rsquo;t even scratch the sponsorship of a niche distro. The documents are still there, in GitHub&rsquo;s template; what ended was the firepower of whoever wielded them. What changed was the money, and yes, the pushback is also money: eight million dollars from eight rich men.</p>
<p>And before someone points out that money doesn&rsquo;t prove merit: it depends. A millionaire made by government cronyism, fraud, or favors has no merit at all. But most millionaires made their money by producing, and that&rsquo;s the case for Omacom&rsquo;s eight patrons. Money earned by producing is the measure of the merit of whoever earned it, as I already wrote here back in 2011, about <a href="/en/2011/02/03/off-topic-a-revolta-de-atlas-dinheiro-e-a-raiz-de-todo-o-mal/">Francisco d&rsquo;Anconia&rsquo;s money speech in &ldquo;Atlas Shrugged&rdquo;</a>.</p>
<blockquote>
  <p>Judge by the result the donation bought, not by the declared intent of whoever signed the check.</p>

</blockquote>
<p>The 49.5 billion corporate dollars from 2020 didn&rsquo;t produce a single extra gram of measurable diversity, the numbers up above prove that. Eight million dollars from individual patrons produced a full-time maintainer writing actual code. The bubble that funded armies of people with no real work popped, and whoever was left was whoever was there for the code.</p>
<h2>The philosophical part<span class="hx:absolute hx:-mt-20" id="the-philosophical-part"></span>
    <a href="#the-philosophical-part" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Let&rsquo;s get to the official excuse: codes of conduct exist to &ldquo;protect minorities.&rdquo; On the surface, who would be against protecting minorities? Not me. The problem is that the phrase is vague by design.</p>
<p>What is a minority? I already translated the chapter <a href="/en/2009/09/09/off-topic-direitos-do-homem/">&ldquo;Man&rsquo;s Rights&rdquo;</a> from Ayn Rand&rsquo;s &ldquo;The Virtue of Selfishness&rdquo; here on the blog. The line that interests me here is from another chapter of the same book, &ldquo;Racism,&rdquo; and it remains unbeatable:</p>
<blockquote>
  <p>The smallest minority on earth is the individual. Those who deny individual rights cannot claim to be defenders of minorities.</p>

</blockquote>
<p>And that&rsquo;s exactly what these codes do in practice: in the name of an abstract, collective minority, the concrete individual gets hunted down. Doxxing (exposing someone&rsquo;s personal data), harassment campaigns, pressure on employers, bans. When the modus operandi for &ldquo;protecting minorities&rdquo; is coordinated bullying against one person until they buckle, you&rsquo;re oppressing the smallest minority there is.</p>
<p>This topic, by the way, is an old one for me. In December 2018 I published the video <a href="/2018/12/05/akitando-31-manifesto-anti-parasita-seja-um-criador/">&ldquo;Anti-Parasite Manifesto: Be a Creator&rdquo;</a> on my channel. At the time I couldn&rsquo;t be explicit, the thought police were still too strong. But whoever watched closely got the message. It was my breadcrumb for this story that I&rsquo;m only now able to tell properly.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/nX0wPjNzn3o"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>And there&rsquo;s the second problem, a more fundamental one: open source is about software. The GPL, which this crowd looks down on so much, solves the one protection a software project can&rsquo;t afford to lose: the code&rsquo;s. It guarantees the code stays free, period. It doesn&rsquo;t ask who wrote it, who they voted for, what they tweeted, what they donated to. The compiler doesn&rsquo;t check for ideological purity. Open source has always been the most inclusive community that ever existed precisely because of this: the only passport was the diff. The code of conduct made open source less inclusive, because it added a new entry criterion: politics. And politics is a stupid criterion for software.</p>
<p>&ldquo;But without a code of conduct, how do we deal with real harassment?&rdquo; With the same tool as always: a maintainer&rsquo;s common sense and, when necessary, the law. If someone directly attacks another person, sexual assault at an event, for example, banning them is common sense and never needed any document. Harassment, threats, and defamation are already crimes in practically every country, and crime gets settled through the law. What I can&rsquo;t stomach is something else: going out and stalking someone&rsquo;s online life to dig up a random opinion, with no relation to any crime, and demanding a ban over words with no criminal consequence. These committees were always great at punishing opinion and terrible at punishing crime, so the document was never about that.</p>
<p>And I&rsquo;m not the only one saying this. Eric S. Raymond, the guy who wrote <a href="http://www.catb.org/~esr/writings/cathedral-bazaar/"target="_blank" rel="noopener">&ldquo;The Cathedral and the Bazaar&rdquo;</a>, the 1997 essay that validated Netscape&rsquo;s decision to open-source Mozilla and that pretty much wrote the rulebook for open source, co-founder of the OSI, editor of the Jargon File, author of fetchmail, went on X in September 2025 to <a href="https://itsfoss.com/news/codes-of-conduct-debate/"target="_blank" rel="noopener">declare the code-of-conduct era a complete failure</a>. In his words: ten years of <em>&ldquo;drama and idiocy&rdquo;</em>, an <em>&ldquo;infectious social insanity&rdquo;</em> that produces politics, intrigue, and negative useful work. The recommendation is as direct as it gets: don&rsquo;t adopt one; if you already did, delete it. And if some bureaucracy forces you to have one, the suggested replacement is a single sentence:</p>
<blockquote>
  <p><em>&ldquo;If you are more annoying to work with than your contributions justify, you&rsquo;ll be ejected.&rdquo;</em></p>

</blockquote>
<p>That&rsquo;s what I said two paragraphs above: a maintainer&rsquo;s common sense.</p>
<p>And the detail that closes the loop: ESR himself had been <a href="https://en.wikipedia.org/wiki/Eric_S._Raymond"target="_blank" rel="noopener">removed from two OSI mailing lists in 2020</a> over posts that &ldquo;violated the code of conduct&rdquo; of the organization he helped found.</p>
<blockquote>
  <p>The guy who wrote the rulebook, ejected by the document. That image sums up the whole era.</p>

</blockquote>
<h2>How we got here<span class="hx:absolute hx:-mt-20" id="how-we-got-here"></span>
    <a href="#how-we-got-here" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>It&rsquo;s worth taking a step back and telling where all this came from, because open source was only one of the fronts. The starting shot, in my reading, was GamerGate, in 2014. In August of that year came the <a href="https://thezoepost.wordpress.com/"target="_blank" rel="noopener">&ldquo;Zoe Post&rdquo;</a>, the ex-boyfriend&rsquo;s rant about developer Zoe Quinn. Twelve days later, and about 48 hours after the #GamerGate hashtag caught fire, <a href="https://www.gamedeveloper.com/business/-gamers-don-t-have-to-be-your-audience-gamers-are-over-"target="_blank" rel="noopener">about a dozen gaming sites published variations of the same article</a>: &ldquo;gamers are over,&rdquo; gamers are dead, it&rsquo;s finished.</p>
<p>Shortly after, the GameJournoPros leaked, a closed group where gaming journalists coordinated coverage. The public realized right away that gaming press had turned into an ideological club, and hit back with their own version of an organized boycott: the &ldquo;Operation Disrespectful Nod&rdquo; campaign flooded Intel with complaints until the company <a href="https://www.theverge.com/2014/10/2/6886747/intel-buckles-to-anti-feminist-campaign-by-pulling-ads-from-gaming"target="_blank" rel="noopener">pulled its ads from Gamasutra</a> (the press at the time called it an &ldquo;anti-feminist campaign&rdquo;; to me it&rsquo;s just organized consumer pressure, the same instrument Sidekiq used against Ruby Central further down the line).</p>
<p>And it&rsquo;s worth pinning down the principle here, because it applies to both sides for the rest of this piece: organized consumer pressure is fair play, no matter which side it comes from. The problem was never pressure. It&rsquo;s doxxing, threatening someone&rsquo;s job, and a committee faking neutrality to impose the result it already wanted before opening the process.</p>
<p>For years, from 2021 to June 2025, Wikipedia&rsquo;s article on the subject lived under the title <a href="https://en.wikipedia.org/wiki/Gamergate"target="_blank" rel="noopener">&ldquo;Gamergate (harassment campaign)&rdquo;</a>, treating any criticism of the journalism as a pretext for harassment. The title got switched back to plain &ldquo;Gamergate&rdquo; once the most hysterical phase had passed, which should be read as a confession, not as if the case were closed: they renamed it back once defending the political label got too costly, the exact same pattern of quiet retreat that shows up throughout this whole story. While it lasted, it lasted for precisely the decade in which that mob had the firepower to make it stick.</p>
<p>The editorial fight got so ugly that Wikipedia&rsquo;s arbitration committee <a href="https://en.wikipedia.org/wiki/Wikipedia:Wikipedia_Signpost/2015-01-28/In_focus"target="_blank" rel="noopener">sanctioned more than a dozen editors, on both sides</a>. And note that I don&rsquo;t even need to accuse Wikipedia on my own: Larry Sanger, co-founder of Wikipedia, wrote the piece <a href="https://larrysanger.org/2020/05/wikipedia-is-badly-biased/"target="_blank" rel="noopener">&ldquo;Wikipedia Is Badly Biased&rdquo;</a> in 2020, declaring the project&rsquo;s neutrality dead, and in September 2025 published <a href="https://larrysanger.org/nine-theses/"target="_blank" rel="noopener">&ldquo;Nine Theses on Wikipedia&rdquo;</a>, calling for reforms like ending source blacklists and ending permanent editor bans. When the founder says the house has been taken over, believe the founder.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260914180253_larry-sanger-akita-2018.jpg" alt="Eu e o Larry Sanger, cofundador da Wikipedia, num evento em outubro de 2018. Uma honra ter podido conhecê-lo pessoalmente."  loading="lazy" /></p>
<p>The gamers&rsquo; side of this story is in the book <a href="https://books.google.com.br/books/about/SJWs_Always_Lie.html?id=NqSUjgEACAAJ&amp;redir_esc=y"target="_blank" rel="noopener">&ldquo;SJWs Always Lie&rdquo;</a>, by Vox Day, from 2015. I already know what&rsquo;s coming: &ldquo;Vox Day&rdquo; and &ldquo;Milo Yiannopoulos&rdquo; are names that make people scream just hearing them, and GameJournoPros, by the way, was also originally broken by that same Milo. I don&rsquo;t care about the reputation of whoever&rsquo;s telling a story, I care whether the story is true. A partisan source from inside the fight, fair warning, but the central fact matches what Wikipedia itself and the press at the time document with zero connection to either of those two names: the GameJournoPros list really did exist, a closed group of about 150 people in games journalism swapping notes on how to cover the case.</p>
<p>The chapter &ldquo;Counterattack&rdquo; tells GamerGate from the inside, and the book&rsquo;s thesis sums up the decade: these people always lie, always double down, always project onto others exactly what they themselves do.</p>
<p>From GamerGate onward, it was dominoes. Anita Sarkeesian turned her Kickstarter from a <a href="https://www.backerkit.com/projects/566429325/tropes-vs-women-in-video-games"target="_blank" rel="noopener">$6,000 goal into $158,000</a>, became a global authority, went to speak at the <a href="https://www.polygon.com/2015/9/25/9399169/united-nations-women-cyber-violence-anita-sarkeesian-zoe-quinn"target="_blank" rel="noopener">UN in 2015</a> about &ldquo;cyber violence,&rdquo; and games journalism never recovered. Her Feminist Frequency <a href="https://www.gamesindustry.biz/anita-sarkeesian-to-close-feminist-frequency-after-15-years"target="_blank" rel="noopener">shut down in 2023</a>, but the logic she kicked off migrated inside the studios: the &ldquo;inclusive narrative&rdquo; consulting industry was born, with Sweet Baby Inc leading the way.</p>
<p>Sweet Baby&rsquo;s CEO, Kim Belair, was recorded at a 2019 GDC talk, a public recording that circulates independently of the site that first surfaced it, advising anyone seeking internal approval for &ldquo;representation&rdquo; consulting to <a href="https://nichegamer.com/sweet-baby-ceo-terrify-them-if-game-devs-dont-push-diversity/"target="_blank" rel="noopener"><em>&ldquo;go grab coffee with the marketing team and terrify them&rdquo;</em></a> with the possibility of what would happen if they didn&rsquo;t get what they wanted. In 2024, a Brazilian created a Steam curator page (Valve&rsquo;s own feature where any account can publish game recommendations and gain followers) named &ldquo;Sweet Baby Inc Detected.&rdquo; One employee at the company individually tried to bring the profile down on their own, and Valve also acted through its own moderation; even so, the result was the group exploding to <a href="https://en.wikipedia.org/wiki/Sweet_Baby_Inc."target="_blank" rel="noopener">more than 350,000 followers</a>.</p>
<p>And then came the flops. Suicide Squad: Kill the Justice League, with <a href="https://en.wikipedia.org/wiki/Sweet_Baby_Inc."target="_blank" rel="noopener">confirmed Sweet Baby consulting</a>, <a href="https://finance.yahoo.com/news/suicide-squad-flop-still-hurting-135841738.html"target="_blank" rel="noopener">cost Warner 200 million dollars in losses</a>. Unknown 9, from the studio where Sweet Baby&rsquo;s founding duo used to work, <a href="https://www.pcgamer.com/gaming-industry/unknown-9-awakening-studio-makes-major-layoffs-just-a-month-after-the-games-release/"target="_blank" rel="noopener">laid off staff en masse a month after launch</a>.</p>
<p>Then came 2020. With BLM, the same playbook became state policy: the 50 biggest American companies <a href="https://finance.yahoo.com/news/corporate-america-pledged-50b-racial-185054221.html"target="_blank" rel="noopener">pledged 49.5 billion dollars</a> in &ldquo;racial justice&rdquo; measures, DEI job postings <a href="https://www.visier.com/blog/chief-diversity-officers-exits/"target="_blank" rel="noopener">grew 123% within months</a>, Biden signed an <a href="https://civilrights.org/biden-timeline/"target="_blank" rel="noopener">&ldquo;equity&rdquo; executive order</a> for the entire federal government on day one of his term, and the European Union rolled out its <a href="https://ec.europa.eu/newsroom/just/items/692134"target="_blank" rel="noopener">2020-2025 anti-racism plan</a>. It was the peak: the patrol had reached the US presidency and the EU&rsquo;s leadership.</p>
<p>The retreat came as fast as the rise. The US Supreme Court <a href="https://www.scotusblog.com/2023/06/supreme-court-strikes-down-affirmative-action-programs-in-college-admissions/"target="_blank" rel="noopener">struck down affirmative action in June 2023</a>, companies <a href="https://www.npr.org/2025/05/27/nx-s1-5307319/dei-jobs-trump"target="_blank" rel="noopener">laid off thousands of DEI professionals</a>, Walmart, Meta, McDonald&rsquo;s, and Amazon dropped their programs, and in January 2025 Trump <a href="https://www.everycrsreport.com/reports/IN12497.html"target="_blank" rel="noopener">revoked the equity orders</a> on day one.</p>
<p>I told all of this just to give context: what happened in open source wasn&rsquo;t an isolated phenomenon. It was the same script, with the same methods, across every culture and tech industry at the same time. The difference is that in open source, the resistance took longer to organize. But it organized.</p>
<h2>My Cortlandt<span class="hx:absolute hx:-mt-20" id="my-cortlandt"></span>
    <a href="#my-cortlandt" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>It was this pressure that pushed me out of organizing RubyConf Brazil. I founded the event in 2008, back when it was still called Rails Summit, and in the last edition I organized, in 2016, we drew 1,500 people. When <a href="/en/2016/09/26/the-next-10-years/">I announced my departure</a>, I wrote that there was no drama involved. That wasn&rsquo;t the whole truth: the patrol had already reached tech conferences, and I refused to turn the event I created into one more stage for it.</p>
<p>Let me give a small example of what it means to be pressured into forcing diversity. As the data I showed above indicates, women are somewhere between 3% and a bit over 13% of open source contributors, depending on how you measure it: self-reported survey or name-based detection in commits. My channel&rsquo;s analytics show the same range, 3 to 5% at most, and that proportion hasn&rsquo;t changed in ten years. Every year I opened a public Call for Papers: anyone could submit a talk. And my selection process <strong>was always blind</strong>: I read every submission without knowing who had sent it, on purpose, so the choice would be based on the merit of the topic and never on the person.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260914175728_youtube-analytics-genero.png" alt="Analytics do meu canal no YouTube, últimos 28 dias: 97% homens, 3% mulheres"  loading="lazy" /></p>
<p>In the patrol years, the pressure was never direct with me. It was that diffuse, external pressure that every event had to be &ldquo;more diverse.&rdquo; And in practice that could only mean one thing: a new phase in the process. After the blind selection, reveal who submitted what, to check whether the lineup was &ldquo;diverse enough.&rdquo; Except that&rsquo;s a mathematical impossibility. Submissions kept following the same 3 to 5%. Even approving every woman who submitted, the imaginary quota didn&rsquo;t add up. The way around it was to go out and invite people directly, choosing by profile instead of by topic.</p>
<p>And the practical result of that scheme, wherever it&rsquo;s applied, is cutting people who got in on merit to open a spot for people chosen by an irrelevant external policy. That drags the event&rsquo;s quality down instead of up. And notice: this isn&rsquo;t an argument against any woman. It&rsquo;s the opposite. The moment the quota enters the process, the doubt stops being about one specific speaker and starts hanging over everyone who steps on stage. It doesn&rsquo;t matter who&rsquo;s talking: if someone in the audience disagrees with the content, there&rsquo;s always the leftover question, &ldquo;did Akita pick this one for the quota?&rdquo; From then on, every speaker carries a suspicion they don&rsquo;t deserve, and everyone&rsquo;s merit gets devalued along with it. It hurts the minority the policy claimed to protect, it hurts the other speakers, it hurts the audience. It&rsquo;s lose-lose all around.</p>
<p>And there&rsquo;s a part of this story nobody sees from outside. Some of the people invited that way turned it down on the spot, &ldquo;because the event wasn&rsquo;t diverse enough.&rdquo; The refusal made the event even less diverse, obviously. And afterward they&rsquo;d go on social media to trash the event, as if I&rsquo;d never invited anyone. That&rsquo;s the level of garbage I had to swallow every year.</p>
<p>And let this be very clear: there&rsquo;s nothing I want more than to see more women in tech. What I can&rsquo;t convince myself of is that forcing a quota, the way I described above, helps with that. Everything I saw in practice points the other way: it hurts more than it helps. And if I don&rsquo;t believe it&rsquo;s beneficial, I&rsquo;d rather not do it.</p>
<p>Want a recent example of a woman I admire in the industry? Asha Sharma, who <a href="https://www.gameshub.com/news/news/xbox-game-pass-cheaper-new-ceo-asha-sharma-2026-2862856/"target="_blank" rel="noopener">took over as Xbox CEO in February</a>. Since then it&rsquo;s been one result after another: <a href="https://www.windowscentral.com/gaming/xbox/microsofts-xbox-ceo-asha-sharma-vows-to-deliver-xbox-updates-every-two-weeks-to-fix-the-fundamentals"target="_blank" rel="noopener">she cut Copilot from the consoles and restructured the division to focus on what matters</a>, <a href="https://www.allkeyshop.com/blog/xbox-first-party-titles-survive-layoffs-news-d/"target="_blank" rel="noopener">sold studios and cut costs without cancelling a single announced game</a>, and this week <a href="https://www.kojimaproductions.jp/en/xbox_partnership_announcement"target="_blank" rel="noopener">brought Kojima Productions to Xbox</a> to publish Hideo Kojima&rsquo;s next game, <a href="https://www.gamespot.com/articles/kojimas-physint-dropped-by-playstation-rescued-by-xbox/"target="_blank" rel="noopener">after PlayStation cancelled the project</a> in mid-2026. Notice the discourse around her: zero mention of &ldquo;gender,&rdquo; zero agenda.</p>
<blockquote>
  <p>Just numbers: cut unnecessary costs, bet on the right calls, improve value for the customer. That&rsquo;s merit. You don&rsquo;t need DEI for that.</p>

</blockquote>
<p>Until I decided enough was enough. Anyone who&rsquo;s read &ldquo;The Fountainhead&rdquo; knows what I did: like Howard Roark, the architect who blows up his own building when they tamper with his design, I dynamited my Cortlandt. More precisely: the event as it existed while it was mine. The brand survived a few more years in other hands, without the same soul, until it disappeared. And I had already <a href="/en/2011/02/04/off-topic-the-fountainhead-defesa-de-howard-roark/">signaled this philosophy here on the blog back in 2011</a>. An individual does nothing for others: he does it for himself. If what you build benefits other people as a side effect, great, but that was never the reason. When the parasites try to take what you built, you blow it all up yourself. Because you can. Whoever built it once builds it again from scratch.</p>
<p>That&rsquo;s what I did. I traded the conference for my YouTube channel, which didn&rsquo;t depend on a sponsor, a committee, or anyone besides me. And the channel grew way beyond anything the conference would ever have become. Then I sat back and waited for the bubble to pop, because I knew it would pop: I wrote it here on the blog and repeated it in videos years before it happened. It popped. Patience always wins.</p>
<h2>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Ten years of codes of conduct, and here&rsquo;s the scoreboard: zero evidence it increased diversity, no toxicity baseline to compare before and after, and the most recent and most rigorous causal study that exists shows the document pushing out old contributors more than it builds new community. The promise was to protect minorities. The delivery was a collection of heads: the creator of JavaScript, the creator of the GPL, the creator of Linux, all put through the public humiliation ritual. None of it over code. All of it over opinion.</p>
<p>And notice how this era ended.</p>
<blockquote>
  <p>The machine didn&rsquo;t lose the argument, it lost its funding.</p>

</blockquote>
<p>It was only once easy money ran out that the armies of people with no real work evaporated, and whoever was left was whoever was there for the code. Meanwhile, the builders kept building: Brendan Eich got pushed out of Mozilla in 2014 and founded Brave the following year, today with more than 100 million monthly active users and a valuation near a billion dollars. DHH lost the keynote and created a bigger conference, lost a third of the company and helped raise an eight-million-dollar foundation. I left my conference and grew far more on my channel. A parasite can take an institution. It can&rsquo;t take the ability to build. Whoever built it once builds it again from scratch.</p>
<p>Open source recruits volunteers who want to contribute code. Any discussion that doesn&rsquo;t involve code is a distraction at best and sabotage at worst. And the answer to &ldquo;what do we put in place of the code of conduct&rdquo; fits in a single sentence, one the ESR already wrote: if you&rsquo;re more trouble to work with than your contributions justify, you&rsquo;re ejected. That&rsquo;s always been how it worked. The only passport is the diff.</p>
<p>The rest is politicking. And politicking, to use the precise technical term, is bullshit.</p>
<p>And here&rsquo;s the final practical recommendation. If your open source project has a <code>CODE_OF_CONDUCT.md</code>, delete the file. If your main branch turned into <code>main</code> in the 2020 wave, rename it back to <code>master</code>. Partly out of spite, I admit. But mostly to exercise the freedom you just got back to do this without being cancelled for it. Freedom you don&rsquo;t exercise atrophies. No clarifying note, no committee vote, no asking anyone&rsquo;s permission. Just because you can again.</p>
]]></content:encoded><category>off-topic</category><category>open-source</category><category>politics</category></item><item><title>AI-MEMORY 2.0 - The Best Memory System for Agents and Teams</title><link>https://akitaonrails.github.io/en/2026/09/02/ai-memory-2-0-best-memory-system-for-agents-and-teams/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/09/02/ai-memory-2-0-best-memory-system-for-agents-and-teams/</guid><pubDate>Wed, 02 Sep 2026 11:00:00 -0300</pubDate><description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;a href="https://github.com/akitaonrails/ai-memory/releases/tag/v2.0.0"target="_blank" rel="noopener"&gt;ai-memory 2.0 is out&lt;/a&gt;, with the open OKF format, local embeddings turned on by default, and real support for several agents and a whole team working on the same project in parallel. The full pitch is below.&lt;/p&gt;
&lt;p&gt;Back in July I published &lt;a href="https://akitaonrails.github.io/en/2026/07/20/whats-new-ai-memory-switch-agents-without-losing-session/"&gt;What&amp;rsquo;s New in My AI-MEMORY&lt;/a&gt;, where I showed off &lt;code&gt;ai-memory run&lt;/code&gt;: switching from Claude Code to Codex without losing your line of work. That day we were on version 1.17.1.&lt;/p&gt;</description><content:encoded><![CDATA[<p><strong>TL;DR:</strong> <a href="https://github.com/akitaonrails/ai-memory/releases/tag/v2.0.0"target="_blank" rel="noopener">ai-memory 2.0 is out</a>, with the open OKF format, local embeddings turned on by default, and real support for several agents and a whole team working on the same project in parallel. The full pitch is below.</p>
<p>Back in July I published <a href="/en/2026/07/20/whats-new-ai-memory-switch-agents-without-losing-session/">What&rsquo;s New in My AI-MEMORY</a>, where I showed off <code>ai-memory run</code>: switching from Claude Code to Codex without losing your line of work. That day we were on version 1.17.1.</p>
<p>Today <strong>2.0</strong> shipped. And this time I&rsquo;m not going to rehash how the hooks work or how a session turns into a wiki page. That&rsquo;s already in the earlier posts. Here I want to talk about where ai-memory landed against the competition, what 2.0 brings, and why it earned the jump to a &ldquo;2&rdquo;.</p>
<p>If you&rsquo;ve never heard of the project, the summary is short. ai-memory is a long-term memory server for your coding agents. It captures what happened in the session, consolidates it into Markdown pages, and hands the right context to the next agent, whatever the harness or the machine.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260902132131_screenshot-2026-09-02_13-20-02.png" alt="ai-memory 2.0 web browser showing the wiki’s project list, with the pre-migration OKF backup notice and cards for several projects like ai-memory, akitaonrails-hugo, and others"  loading="lazy" /></p>
<p>This is the web interface that comes with it, handy for auditing what the agents wrote and for browsing between projects. Notice how each project lives separately, with its own page count, all of it coming out of real sessions.</p>
<h2>Why it became 2.0<span class="hx:absolute hx:-mt-20" id="why-it-became-20"></span>
    <a href="#why-it-became-20" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For me, the first digit of a version carries a commitment.</p>
<p>The 1.x line grew too fast. We went from 1.1 to 1.39 in a little over two months, stacking feature on top of feature in minor releases. It worked for iterating, but it blurred what the numbers meant.</p>
<p>2.0 fixes that. It bundles the few compatibility-breaking changes into a single major, and from here on versioning follows real <a href="https://github.com/akitaonrails/ai-memory/blob/main/CONTRIBUTING.md"target="_blank" rel="noopener">Semantic Versioning</a>. A fix is a patch. A new feature is a minor. Only a format or contract break is a major, and always with warning. The new contributing guide spells that rule out for any PR.</p>
<p>The main break is the new on-disk format. The first time you bring up 2.0, it migrates your wiki on its own. Before touching anything, it compresses your entire data directory into a verified backup with the date in the name. If the backup can&rsquo;t be written and checked, the migration aborts and the server refuses to start. No &ldquo;trust me&rdquo;.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260902131952_screenshot-2026-09-02_13-16-17.png" alt="ai-memory 2.0 dialog announcing that the memory was migrated to the OKF v0.2 format, showing the verified backup path and the rollback steps"  loading="lazy" /></p>
<p>This is the notice that shows up once, right after the migration: it tells you where the backup landed, the file size, and how to roll back if something looks off. Once you confirm everything is fine, you just delete the backup and the reminder disappears.</p>
<h2>OKF: your memory isn&rsquo;t locked inside ai-memory<span class="hx:absolute hx:-mt-20" id="okf-your-memory-isnt-locked-inside-ai-memory"></span>
    <a href="#okf-your-memory-isnt-locked-inside-ai-memory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the change that made me happiest.</p>
<p>Starting with 2.0, the ai-memory wiki is, natively, a bundle in the <strong>Open Knowledge Format</strong>, the open format Google published in 2026. Each memory page is a valid OKF file: plain Markdown with standardized metadata. There&rsquo;s no export step that produces a divergent copy. The wiki files already are the OKF files.</p>
<p>In practice that means your memory stopped being a hostage of my project. You can read it all with <code>grep</code>, open it in Obsidian, version it in Git, or hand the bundle to a coworker who uses another OKF-compatible tool. There&rsquo;s even an <code>ai-memory export-okf</code> to package a whole project into a validated tarball.</p>
<p>That was always the thesis: the model and the harness are rented, the project&rsquo;s memory is yours. Now the format backs that up in writing.</p>
<h2>Local embeddings, on by default<span class="hx:absolute hx:-mt-20" id="local-embeddings-on-by-default"></span>
    <a href="#local-embeddings-on-by-default" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Up through 1.x, real semantic search depended on you configuring an embeddings provider. Either you paid for an API and sent every page and every query out, or you spun up an Ollama on the side. Both options have a cost.</p>
<p>2.0 brings a <code>local</code> provider that runs the embeddings model inside the process itself, in pure Rust, with <code>all-MiniLM-L6-v2</code>. No API key, no external server, no GPU, and nothing about your data leaving the box. And now it comes on by default. On the first run it downloads the model (about 87 MB, with a fixed checksum) in the background and turns on hybrid search at the next restart.</p>
<p>The gain is measurable. On the LongMemEval-S benchmark, hit@5 goes from 0.617 with full-text only to 0.779 with the local embeddings. If for some reason you don&rsquo;t want it, an <code>embedding_provider = &quot;none&quot;</code> turns it off.</p>
<p>A detail that matters: I chose <code>candle</code> on purpose, instead of the native runtime the competition uses. That native layer is exactly what caused a recurring kind of crash in other memory projects. I preferred not to inherit the problem.</p>
<h2>Several agents at once, on the same project<span class="hx:absolute hx:-mt-20" id="several-agents-at-once-on-the-same-project"></span>
    <a href="#several-agents-at-once-on-the-same-project" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s where the part that drove most of the work before 2.0 begins.</p>
<p>The <code>ai-memory run</code> case I showed in July was sequential: I close Claude, open Codex, keep going. But what about when I leave two or three harnesses open at the same time on the same project? Claude in one tab, Codex in another, OpenCode in a third.</p>
<p>ai-memory handles that without anyone stepping on anyone else. Each memory call figures out on its own which project it belongs to, from the session&rsquo;s directory. The &ldquo;current project&rdquo; pointer is now per actor, so two harnesses in the same checkout each keep their own sense of context. And the project&rsquo;s identity comes from the checkout name. The absolute path on disk doesn&rsquo;t count, so the same project on the laptop and on the desktop lands in the same place.</p>
<p>When two windows write to the same page, the second doesn&rsquo;t erase the first. It creates a new version that becomes the latest, and the previous one stays reachable in the version chain. Writing something identical doesn&rsquo;t create a new version. Every write goes through a single writer, with a queue and backpressure, so a burst doesn&rsquo;t corrupt anything.</p>
<p>This isn&rsquo;t theory. There&rsquo;s an acceptance test calling Claude, Codex, OpenCode, Pi, Crush, and a few others for real, inside a single workstream, covering leases, session adoption, and context handoff between harnesses.</p>
<h2>A whole team on the same project<span class="hx:absolute hx:-mt-20" id="a-whole-team-on-the-same-project"></span>
    <a href="#a-whole-team-on-the-same-project" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The second scenario is the one that gives the post its title. Here it&rsquo;s several people, a whole team pointing their agents at the same server.</p>
<p>The way to run it is simple. Someone brings up a server, usually a container in a homelab or on a machine on the network, and each person points their agents at that URL. HTTPS goes in front with a reverse proxy, if you want. The database is still a single SQLite.</p>
<p>Everyone sees the same project pages. What one person learned in a session, the other&rsquo;s agent recovers. And each new session gets a briefing with the project&rsquo;s state right at the start. I&rsquo;ll be honest about the term &ldquo;real time&rdquo;. What exists is a shared central store, with immediate reads, plus the briefing at the open. The note a coworker wrote shows up right away for anyone&rsquo;s next query or next session. A session that&rsquo;s already running only gets the news at the next query or the next open, with no interruption mid-flight.</p>
<p>What changes in multi-user mode is attribution. Each write records who did it. There&rsquo;s an audit log and the interface shows &ldquo;edited by so-and-so&rdquo;. That comes in the box, for free. And there&rsquo;s no per-page permission, on purpose. Attribution is there to record authorship; anyone authenticated can write, and the history is what keeps track of who did.</p>
<p>There&rsquo;s an important security distinction between what&rsquo;s shared and what&rsquo;s personal. The pages belong to everyone. But the handoff is a baton with a single owner: exactly one session takes it, and a second <code>accept</code> doesn&rsquo;t steal the baton from anyone. The handoff you left pending isn&rsquo;t delivered to or consumed by a coworker. Likewise, the &ldquo;what I&rsquo;m working on right now&rdquo; slots are per person, so your personal context doesn&rsquo;t leak into the whole team&rsquo;s briefing.</p>
<p>There&rsquo;s also a battery of real concurrency tests covering these cases: simultaneous writes, per-actor isolation under load, the handoff baton that doesn&rsquo;t get stolen, and the personal slots that don&rsquo;t leak.</p>
<h2>Where ai-memory stands against the competition<span class="hx:absolute hx:-mt-20" id="where-ai-memory-stands-against-the-competition"></span>
    <a href="#where-ai-memory-stands-against-the-competition" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before 2.0 we did another round of research on the 2026 landscape, documented in the repository. It was the basis for deciding what 2.0 needed to cover. Let me summarize the field.</p>
<p>There&rsquo;s <strong>agentmemory</strong>, a TypeScript MCP server tied to a native sidecar and a giant surface of dozens of tools. There&rsquo;s <strong>basic-memory</strong>, in Python, Markdown on disk, but with manual capture: you have to ask it to remember. There&rsquo;s <strong>cognee</strong>, which combines graph, vector, and relational into a heavy pipeline that wants several gigs of RAM. There&rsquo;s <strong>MemPalace</strong>, which went viral with almost 50,000 stars in two weeks over a benchmark number that, once audited, turned out to be inflated, on top of suffering corruption when two writes happen together. And there are the temporal graphs like <strong>Zep</strong>, the &ldquo;memory OS&rdquo; like <strong>Letta</strong> (the old MemGPT), and the fact extractors like <strong>Mem0</strong>.</p>
<p>There&rsquo;s also the native memory that Claude Code itself started turning on by default. I treat that one as the funnel that introduces the category to people. As a competitor it stays limited: tied to one machine, tied to one agent, without real search and without team history.</p>
<p>2.0 closes the gaps the research pointed out. We started publishing a reproducible benchmark with LongMemEval, running the actual server. We got the open OKF format. We got typed links between pages, with <code>causes</code>, <code>fixes</code>, and <code>contradicts</code>, which also feed a contradiction check without spending an LLM. We got queries with <code>as_of</code>, to ask what we knew about a subject on a given date. We got the local embeddings. And we got an optional &ldquo;experience&rdquo; pass that reviews several sessions to find patterns that only show up across the set.</p>
<p>Now the part that matters for whoever&rsquo;s choosing. What ai-memory has that the others don&rsquo;t, all together:</p>
<ul>
<li><strong>It follows you across agents.</strong> More than twenty harnesses feed a single memory, and the handoff here is a real protocol: typed, with an owner, and claimed exactly once.</li>
<li><strong>It follows you across machines.</strong> The memory lives on a server that&rsquo;s yours. The project you dropped on the desktop is the one you pick back up on the laptop.</li>
<li><strong>It works for a team.</strong> Multi-user authentication, per-person attribution, and an audit log come in the box, for free.</li>
<li><strong>Your memory is plain Markdown.</strong> The source of truth is a wiki versioned in Git. The database is a derived index you can rebuild at any moment from the files, with no vector store to babysit and nothing trapped in a binary blob.</li>
<li><strong>It captures the work on its own, quietly.</strong> No &ldquo;remember this&rdquo; ceremony. And the default path runs with zero LLM calls.</li>
<li><strong>It&rsquo;s a single binary.</strong> No sidecar, no three databases to sync. Every write goes through a single writer, with a write ceiling we actually measured, with a real test. That design is exactly what avoided the concurrent-write corruption that took the others down.</li>
</ul>
<p>No competitor delivers this set. Some have one piece or another. ai-memory has the whole package, and now with parity on the items where it used to fall behind.</p>
<h2>2.0 belongs to everyone<span class="hx:absolute hx:-mt-20" id="20-belongs-to-everyone"></span>
    <a href="#20-belongs-to-everyone" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When I wrote the July post, fifteen people had a merged PR in the project. Today it&rsquo;s around seventy. This stopped being a weekend project a long time ago.</p>
<p>The numbers up to 2.0: more than 1,500 commits, <strong>371 merged pull requests</strong>, and <strong>181 closed issues</strong>. That came from people actually using it and sending fixes, features, and documentation.</p>
<p>I have to give special thanks to <a href="https://github.com/djalmajr"target="_blank" rel="noopener">Djalma Júnior</a>, who on his own passed 50 merged PRs, and to <a href="https://github.com/samirhvbr"target="_blank" rel="noopener">Samir Hanna Verza</a>, with more than 20. Right behind come <a href="https://github.com/lhzapata"target="_blank" rel="noopener">lhzapata</a>, <a href="https://github.com/pedrofjr"target="_blank" rel="noopener">pedrofjr</a>, <a href="https://github.com/mrpaiva"target="_blank" rel="noopener">mrpaiva</a>, <a href="https://github.com/lucasliet"target="_blank" rel="noopener">lucasliet</a>, <a href="https://github.com/lihuiyang1024"target="_blank" rel="noopener">lihuiyang1024</a>, <a href="https://github.com/Murillofilho86"target="_blank" rel="noopener">Murillofilho86</a>, and <a href="https://github.com/matheus-rodrigues00"target="_blank" rel="noopener">Matheus Rodrigues</a>. And there&rsquo;s a long tail of dozens of other people with a merged PR that it would be unfair to try to list in full here.</p>
<p>If you want in on this, the <a href="https://github.com/akitaonrails/ai-memory/blob/main/CONTRIBUTING.md"target="_blank" rel="noopener">contributing guide</a> was rewritten to make everything clear: how to set up the environment, the gates the CI enforces, the CHANGELOG rule, and the versioning policy. A bug fix usually ships fast in the next patch. A small feature, like a new harness or provider, goes into the next minor. There are issues tagged for people just starting out.</p>
<h2>How to get 2.0<span class="hx:absolute hx:-mt-20" id="how-to-get-20"></span>
    <a href="#how-to-get-20" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The project page has every install method, including AUR, Homebrew, and release binaries:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory on GitHub</a></li>
<li><a href="https://github.com/akitaonrails/ai-memory/releases/tag/v2.0.0"target="_blank" rel="noopener">v2.0.0 release notes</a></li>
</ul>
<p>After updating, on the first run let the migration take the backup and convert your wiki to the OKF format. If you use the managed mode, reinstall the hooks for the harnesses you plan to use.</p>
<h2>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>1.x proved the idea worked. 2.0 is the version I&rsquo;d recommend without an asterisk for someone else to put on a team.</p>
<p>The format is open, so your memory doesn&rsquo;t get locked in. Semantic search runs local, so you don&rsquo;t pay and you don&rsquo;t leak. Several agents and several people work on the same project without running each other over. And the single-binary, single-writer design is what avoids exactly the problems that sank half the competition.</p>
<p>The LLM and the subscription I keep renting from whoever&rsquo;s best that month. The project&rsquo;s memory stays with me, with the team, and now in a format nobody can take away from me.</p>
]]></content:encoded><category>ai-memory</category><category>coding-agents</category><category>open-source</category></item><item><title>Removing DRM from Kindle Ebooks in 2026</title><link>https://akitaonrails.github.io/en/2026/07/30/removing-drm-from-kindle-ebooks-in-2026/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/07/30/removing-drm-from-kindle-ebooks-in-2026/</guid><pubDate>Thu, 30 Jul 2026 18:00:00 -0300</pubDate><description>&lt;p&gt;I&amp;rsquo;ve been an Amazon customer for far too long. I&amp;rsquo;ve bought Kindle books for years, owned several of their devices, and I still hate the way the company treats digital content.&lt;/p&gt;
&lt;p&gt;You pay for a book, but you can only read it where Amazon allows. There is no decent native Linux app. Moving to another reader turns into an exercise in archaeology. I bought a new Xteink X4 and, naturally, my library couldn&amp;rsquo;t simply come along. The file was &amp;ldquo;in my account,&amp;rdquo; but it wasn&amp;rsquo;t under my control.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;ve been an Amazon customer for far too long. I&rsquo;ve bought Kindle books for years, owned several of their devices, and I still hate the way the company treats digital content.</p>
<p>You pay for a book, but you can only read it where Amazon allows. There is no decent native Linux app. Moving to another reader turns into an exercise in archaeology. I bought a new Xteink X4 and, naturally, my library couldn&rsquo;t simply come along. The file was &ldquo;in my account,&rdquo; but it wasn&rsquo;t under my control.</p>
<p>For years, I worked around this through the official route. I&rsquo;d sign into Amazon&rsquo;s website, use <strong>Download &amp; Transfer via USB</strong>, download the <code>.azw</code> files for books I&rsquo;d bought, and import everything into <a href="https://calibre-ebook.com/about"target="_blank" rel="noopener">calibre</a>. With the DeDRM plugin configured for my Kindle&rsquo;s serial number, I&rsquo;d convert them to EPUB and be done with it.</p>
<p>On <strong>February 26, 2025</strong>, Amazon <a href="https://www.vice.com/en/article/amazon-is-killing-your-ability-to-download-kindle-books-next-week/"target="_blank" rel="noopener">shut that option down</a>. No decent announcement, no replacement that actually handed over the file, and no concern for anyone who wanted a local backup. My newer books have been trapped in their ecosystem ever since. I tried again last year, updated the plugin, copied files from my Kindle Paperwhite, entered the correct serial number, and got nowhere.</p>
<p>To be fair, on <strong>January 20, 2026</strong>, Amazon began allowing verified buyers to download EPUB or PDF files when the publisher <a href="https://kdp.amazon.com/pt_BR/help/topic/GDDXGH9VR22ACM8U"target="_blank" rel="noopener">marks the book as DRM-free</a>. Great. That doesn&rsquo;t help with protected books, and the decision still belongs to the publisher. Older DRM-free titles must also be confirmed one by one by the publisher. This did not magically add a download button to my library.</p>
<p>I decided to try again now. The new DeDRM version can handle the current DRM, but the process has changed quite a bit. It takes work, requires Windows for one step, and relies on a community tool still in pre-release. It worked. I recovered <strong>106 books I&rsquo;d bought</strong>, tested the EPUB conversion, and can now read them on whatever device I choose.</p>
<p>This is the state of play on <strong>July 30, 2026</strong> (updated August 19). Amazon could change the encryption or the app tomorrow. Ignore old tutorials telling you to install Kindle for PC 1.17, disable updates, and enter the device serial number in Calibre. That world is gone.</p>
<p>And let&rsquo;s get the obvious out of the way: I&rsquo;m talking about books <strong>I bought</strong>. I&rsquo;m not talking about downloading Kindle Unlimited titles, library loans, or somebody else&rsquo;s books. Laws covering DRM circumvention vary by country. Check the law where you live and take responsibility for what you do.</p>
<h2>First things first: don&rsquo;t throw out an old Kindle<span class="hx:absolute hx:-mt-20" id="first-things-first-dont-throw-out-an-old-kindle"></span>
    <a href="#first-things-first-dont-throw-out-an-old-kindle" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Amazon doesn&rsquo;t make it easy to repurpose an old Kindle either. The hardware remains perfectly good, the battery is usually replaceable, and an e-ink screen lasts forever, yet the software becomes increasingly closed and limited.</p>
<p>If you want to revive one of these devices, I recommend the <a href="https://www.youtube.com/@DammitJeff"target="_blank" rel="noopener">Dammit Jeff</a> channel. He covers jailbreaks, KOReader, alternative stores, and ways to keep Kindles useful after Amazon loses interest. His video about <a href="https://www.youtube.com/watch?v=l4ZliC82RtA"target="_blank" rel="noopener">AdBreak and recent jailbreaks</a> is a good place to start. Read the <a href="https://kindlemodding.org/"target="_blank" rel="noopener">current Kindle Modding guide</a> before doing anything, because supported firmware and methods change constantly.</p>
<p>Jailbreaking the device and removing DRM from an ebook are separate problems. You do not need to unlock your Kindle to follow the rest of this article. I mention both because they start from the same premise: hardware and media we&rsquo;ve already paid for should remain useful without asking the manufacturer for eternal permission.</p>
<h2>Crash course: AZW, EPUB, and KFX<span class="hx:absolute hx:-mt-20" id="crash-course-azw-epub-and-kfx"></span>
    <a href="#crash-course-azw-epub-and-kfx" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>DRM and file format are separate things. The format defines how text, images, fonts, the table of contents, and metadata are packaged. DRM adds a cryptographic lock on top and decides which account, app, or device can open it.</p>
<p>These are the three names that matter here:</p>
<table>
  <thead>
      <tr>
          <th>Format</th>
          <th>What it is</th>
          <th>In practice</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>AZW / AZW3</strong></td>
          <td>An older family of proprietary Kindle formats. AZW3 is also known as Kindle Format 8.</td>
          <td>This is what normally came through the old USB download. Tools and alternative readers understand it well after the DRM is removed.</td>
      </tr>
      <tr>
          <td><strong>EPUB</strong></td>
          <td>An open W3C standard. It is a single package containing HTML-based content, CSS, SVG, fonts, and metadata.</td>
          <td>It is the most portable format for storage and reading outside Amazon&rsquo;s ecosystem. This is the destination I want.</td>
      </tr>
      <tr>
          <td><strong>KFX</strong></td>
          <td>Amazon&rsquo;s modern delivery format, used for features such as Enhanced Typesetting and Page Flip. A purchased book may be split across several containers, auxiliary resources, and a DRM voucher.</td>
          <td>This is what the current Kindle app downloads. We need to gather the pieces, remove the DRM, and only then convert it.</td>
      </tr>
  </tbody>
</table>
<p>The extension alone can be misleading. Pieces of a KFX book may show up as <code>.azw</code>, <code>.azw.res</code>, <code>.voucher</code>, and other variations. The <a href="https://www.mobileread.com/forums/showthread.php?t=291290"target="_blank" rel="noopener">KFX Input</a> plugin exists specifically to understand that bundle.</p>
<p>EPUB is much less mysterious. The <a href="https://www.w3.org/TR/epub-33/"target="_blank" rel="noopener">EPUB 3.3 specification</a> defines it as a single-file container for structured Web content. It&rsquo;s basically a small packaged website. Any halfway decent reader can support it without depending on a secret Amazon key.</p>
<h2>Calibre and the two plugins<span class="hx:absolute hx:-mt-20" id="calibre-and-the-two-plugins"></span>
    <a href="#calibre-and-the-two-plugins" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://calibre-ebook.com/"target="_blank" rel="noopener">calibre</a> is the Swiss Army knife of ebooks. It&rsquo;s open source, runs on Linux, macOS, and Windows, organizes libraries, fetches metadata, edits covers, transfers books, and converts dozens of formats. It has been around since 2006 and was born precisely because the first Sony Reader didn&rsquo;t work properly on Linux.</p>
<p>On Omarchy or any other Arch system, install the package:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S calibre</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>For other distributions, see the <a href="https://calibre-ebook.com/download"target="_blank" rel="noopener">official download page</a>. Don&rsquo;t install some random package from a download site.</p>
<p>One gotcha for environments using <code>mise</code>: if Calibre dies with <code>ModuleNotFoundError: msgpack</code> or <code>BrokenPipeError</code>, a Python shim probably got ahead of <code>/usr/bin</code>. The Arch package needs the system Python. Start it like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">env <span class="nv">PATH</span><span class="o">=</span><span class="s2">&#34;/usr/bin:</span><span class="nv">$PATH</span><span class="s2">&#34;</span> /usr/bin/python3 /usr/bin/calibre</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This has nothing to do with DRM or the plugins. It&rsquo;s just Calibre&rsquo;s helper calling the wrong Python. I left a permanent launcher with this <code>PATH</code> on my desktop.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-library-epub.webp" alt="My Calibre library with a converted book available in both AZW3 and EPUB."  loading="lazy" /></p>
<p>Calibre alone does not remove DRM. We need two plugins:</p>
<ol>
<li><strong>DeDRM</strong> recognizes and removes locks from several ecosystems during import. It only runs when the book enters the library. Clicking Convert afterward removes nothing.</li>
<li><strong>KFX Input</strong> understands Amazon&rsquo;s modern containers, gathers the pieces of a book, and makes EPUB conversion possible.</li>
</ol>
<p>At the time of writing, I&rsquo;m using <strong>DeDRM 10.0.28</strong>, published on July 14 in the <a href="https://github.com/Satsuoni/DeDRM_tools/releases/tag/v10.0.28"target="_blank" rel="noopener">fork maintained by Satsuoni</a>. It is a pre-release. Download the asset named <code>DeDRM_tools.zip</code>, never a standalone executable from some obscure mirror.</p>
<p><strong>Update (August 2026):</strong> the Kindle app on the Microsoft Store keeps moving, and each new app version requires a new version of the tool. Since this article was published, the app moved past 1.0.18632: <a href="https://github.com/Satsuoni/DeDRM_tools/releases/tag/v10.0.29"target="_blank" rel="noopener">10.0.29</a> added support for app 1.22326, and <a href="https://github.com/Satsuoni/DeDRM_tools/releases/tag/v10.0.30"target="_blank" rel="noopener">10.0.30</a> supports app 1.0.22920. The practical rule is a single one: the executable&rsquo;s name carries the app version it understands (<code>MSIXKFXArchiverMobi1_22920.exe</code> for Store app 1.0.22920, and so on). Before you start, always check the <a href="https://github.com/Satsuoni/DeDRM_tools/releases"target="_blank" rel="noopener">releases page of Satsuoni&rsquo;s fork</a> and grab the <strong>newest</strong> pre-release. Everything else in the process described here stays the same.</p>
<p>I extracted everything into a directory that would later be shared with the Windows VM:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p ~/Windows/Kindle-DeDRM/v10.0.28
</span></span><span class="line"><span class="cl">unzip ~/Downloads/DeDRM_tools.zip -d ~/Windows/Kindle-DeDRM/v10.0.28</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The SHA-256 for the <code>DeDRM_tools.zip</code> I used was:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">520cce704edf9ae26e43196efe2871daf9b25d6cb489aa56051626801c362947</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Check it with <code>sha256sum</code>. This doesn&rsquo;t magically turn a community binary into safe software, but it at least confirms that you&rsquo;re using the same file I tested.</p>
<p>Inside that directory is <code>DeDRM_plugin.zip</code>. <strong>Do not extract this second ZIP.</strong> In Calibre, open <strong>Preferences → Plugins → Load plugin from file</strong>, choose <code>DeDRM_plugin.zip</code>, accept the warning, and restart the program.</p>
<p>Then go back to <strong>Preferences → Plugins → Get new plugins</strong>, search for <strong>KFX Input</strong>, and install it. My test used version <strong>2.33.0</strong>. Restart again.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-plugins-dedrm-kfx.webp" alt="Calibre 9.11 with DeDRM 10.0.28 and KFX Input 2.33.0 installed."  loading="lazy" /></p>
<h2>Why copying from the Kindle over USB didn&rsquo;t work<span class="hx:absolute hx:-mt-20" id="why-copying-from-the-kindle-over-usb-didnt-work"></span>
    <a href="#why-copying-from-the-kindle-over-usb-didnt-work" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The simplest path would still be plugging in my new Kindle Paperwhite, copying the book, and configuring the device serial number in DeDRM. That was the first thing I tried.</p>
<p>The file came in as <code>KFX-ZIP</code>, the plugin ran, but it remained encrypted. I opened Calibre in debug mode and the log showed that the book used the <code>ACCOUNT_SECRET</code> strategy. The serial number was correct. The required key no longer came from the device alone.</p>
<p>That&rsquo;s why so many people follow an old tutorial, try five different serial numbers, and conclude that DeDRM is broken. New books with this DRM need the secret stored by the current Kindle app on Windows. That secret is protected by TPM APIs.</p>
<h2>A disposable Windows inside Omarchy<span class="hx:absolute hx:-mt-20" id="a-disposable-windows-inside-omarchy"></span>
    <a href="#a-disposable-windows-inside-omarchy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I&rsquo;m not keeping a dual-boot setup just to download ebooks. I&rsquo;m also not going to pretend Wine runs everything. Fortunately, Omarchy <a href="https://learn.omacom.io/books/2/pages/100"target="_blank" rel="noopener">already ships with everything needed to install and launch a Windows VM</a>: it appears in the Omarchy menu, opens over RDP, and automatically shares <code>~/Windows</code> with the guest. I didn&rsquo;t have to build this integration from scratch.</p>
<p>Underneath, it uses <a href="https://github.com/dockur/windows"target="_blank" rel="noopener">dockur/windows</a>. Dockur packages QEMU/KVM inside a container and automates the Windows installation. It remains a real virtual machine with its own disk and kernel. The container handles distribution, configuration, and lifecycle.</p>
<p>To install it from the terminal, run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">omarchy-windows-vm install</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Choose the RAM, CPU count, and disk size. The installer creates <code>~/.config/windows/docker-compose.yml</code>, stores the virtual disk in <code>~/.windows</code>, and shares <code>~/Windows</code> with the guest. Inside Windows, that directory appears as <strong>Shared</strong>, usually on <code>Z:</code>, and is also available at <code>\\host.lan\Data</code>.</p>
<p>The detail that mattered in my case was enabling <strong>TPM 2.0</strong>. Edit the generated Compose file and add <code>TPM: &quot;Y&quot;</code> to the <code>environment</code> block:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">windows</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">dockurr/windows</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">VERSION</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;11&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">TPM</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Y&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then recreate the container. The Windows disk remains in the persistent volume:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">omarchy-windows-vm stop
</span></span><span class="line"><span class="cl">omarchy-windows-vm launch -k</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The <code>-k</code> keeps the VM running after you close RDP. You can also watch it boot in a browser at <code>http://127.0.0.1:8006</code>.</p>
<!-- Screenshot pending: Windows 11 in dockur, open through Omarchy. -->
<h2>Downloading the books with the right app<span class="hx:absolute hx:-mt-20" id="downloading-the-books-with-the-right-app"></span>
    <a href="#downloading-the-books-with-the-right-app" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Inside Windows, open the Microsoft Store and install <strong><a href="https://apps.microsoft.com/detail/9p8jq0jjstll"target="_blank" rel="noopener">Amazon Kindle: Reading App</a></strong>, product <code>9P8JQ0JJSTLL</code>.</p>
<p>Pay attention here. The old Kindle for PC installer found on blogs is not the same app. The tool I used looks for the Microsoft Store package <code>AMZNKindle.AmazonKindleReadingApp</code>. With the legacy program, it simply replies <code>No AmazonKindleReadingApp installation found</code>.</p>
<p>Sign in to your account and download every book you want to preserve. Opening the cover or seeing the title in your library isn&rsquo;t enough. The content must be available offline inside the app.</p>
<p>Unfortunately, the most annoying part is still manual. Amazon found room for a one-click purchase button, but apparently not for a &ldquo;download everything I&rsquo;ve paid for&rdquo; button.</p>
<p>I did this for 106 books. Yes, it was a pain in the ass.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/kindle-store-library.webp" alt="The Microsoft Store Kindle app with the ebooks downloaded to its local library."  loading="lazy" /></p>
<h2>Generating KFX-ZIP files and the K4I key<span class="hx:absolute hx:-mt-20" id="generating-kfx-zip-files-and-the-k4i-key"></span>
    <a href="#generating-kfx-zip-files-and-the-k4i-key" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The <code>DeDRM_tools.zip</code> we extracted on Linux is already visible in Windows through the shared directory. Open PowerShell and switch to that directory:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">cd </span><span class="p">\\</span><span class="n">host</span><span class="p">.</span><span class="n">lan</span><span class="p">\</span><span class="n">Data</span><span class="p">\</span><span class="nb">Kindle-DeDRM</span><span class="p">\</span><span class="n">v10</span><span class="p">.</span><span class="py">0</span><span class="p">.</span><span class="py">28</span>
</span></span><span class="line"><span class="cl"><span class="p">.\</span><span class="n">MSIXKFXArchiverMobi1_18632</span><span class="p">.</span><span class="n">exe</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The banner may still mention an older <code>1.0.15230</code> build. The versioned executable above looks for Store app <code>1.0.18632</code>, and that&rsquo;s the one that worked for me. The number in the file name must match <strong>your</strong> app version: if the Store already delivered a newer one, download the matching release from the project&rsquo;s page (see the update in the plugins section).</p>
<p>This executable finds the current Microsoft Store app&rsquo;s cache, gathers each book&rsquo;s components, and produces two things:</p>
<ul>
<li><code>archived_kfx/</code>, containing one <code>.kfx-zip</code> for every downloaded ebook;</li>
<li><code>oldbooks.k4i</code>, the keyfile DeDRM needs to open those files.</li>
</ul>
<p>On my machine, the process found and archived <strong>106 books</strong>. The SHA-256 of the executable I ran was:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0c78b45ccea2c36a5fbb01b9f66bdd9e5d5960a68a340ba2ee96e138f5cddf4a</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It is a 32-bit binary. If it complains about a missing <code>MSVCP140.dll</code>, install the <a href="https://aka.ms/vc14/vc_redist.x86.exe"target="_blank" rel="noopener">official Microsoft Visual C++ Redistributable x86</a>. Do not hunt for a loose DLL on Google. That&rsquo;s a great way to turn a book backup into a malware backup.</p>
<p>The <code>oldbooks.k4i</code> file is sensitive. It is derived from your account secret in that Kindle installation. Do not publish it, attach it to a GitHub issue, screenshot its contents, or put it in a public repository.</p>
<!-- Screenshot pending: PowerShell after the archiver generates archived_kfx and oldbooks.k4i. -->
<h2>Configuring the key in DeDRM<span class="hx:absolute hx:-mt-20" id="configuring-the-key-in-dedrm"></span>
    <a href="#configuring-the-key-in-dedrm" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Back on Linux, open Calibre and follow this path:</p>
<p><strong>Preferences → Plugins → DeDRM → Customize plugin → Kindle for Mac/PC ebooks → Import Existing Keyfiles</strong></p>
<p>Select:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">~/Windows/Kindle-DeDRM/v10.0.28/oldbooks.k4i</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Use <strong>Import Existing Keyfiles</strong>. Do not use the generic <strong>Set Keyfile</strong> button on the main screen. It records a different kind of key candidate and does not register the K4I key in the right place.</p>
<p>Close the key list, click <strong>OK</strong> in the main configuration window, and restart Calibre. If you close it with Cancel, it quietly throws the change away.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-dedrm-key.webp" alt="DeDRM with the oldbooks keyfile imported into the Kindle for Mac/PC key list."  loading="lazy" /></p>
<h2>Importing and converting to EPUB<span class="hx:absolute hx:-mt-20" id="importing-and-converting-to-epub"></span>
    <a href="#importing-and-converting-to-epub" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before dumping a hundred files into the library, test one.</p>
<p>Choose a <code>.kfx-zip</code> from:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">~/Windows/Kindle-DeDRM/v10.0.28/archived_kfx/</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Use <strong>Add books</strong> in Calibre. Internally, the order is:</p>
<ol>
<li>KFX Input recognizes the package;</li>
<li>DeDRM tries the K4I keys during import;</li>
<li>KFX Input assembles the decrypted book as KFX;</li>
<li>Calibre can now open and convert the result.</li>
</ol>
<p>If the format still appears as <code>KFX-ZIP</code>, it failed. Clicking Convert ten times won&rsquo;t help. Remove that entry from the library, fix the plugin or key, and import it again. DeDRM only acts on <strong>input</strong>.</p>
<p>When the book appears as <code>KFX</code>, open it in the viewer and check a few pages. Then click <strong>Convert books</strong>, choose <strong>EPUB</strong> as the output, and test the resulting file on the reader you plan to use. Only then should you run the batch import.</p>
<p>In my case, the KFX opened, converted, and the EPUB worked outside Kindle. That told me the entire path was working: Microsoft Store, TPM, archiver, K4I, DeDRM 10.0.28, and KFX Input 2.33.0.</p>
<!-- Screenshot pending: book imported as KFX in Calibre. -->
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/30/kindle-dedrm/calibre-convert-epub.webp" alt="Calibre’s conversion dialog with EPUB selected as the output format."  loading="lazy" /></p>
<!-- Screenshot pending: final EPUB open on the Xteink X4. -->
<h2>Back up what actually matters<span class="hx:absolute hx:-mt-20" id="back-up-what-actually-matters"></span>
    <a href="#back-up-what-actually-matters" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>After the conversion, I preserve three things:</p>
<ul>
<li>the final EPUBs, which I can read on any device;</li>
<li>the original KFX-ZIP files, until I&rsquo;ve verified that every EPUB is intact;</li>
<li><code>oldbooks.k4i</code>, encrypted and stored separately from the library.</li>
</ul>
<p>My plaintext keyfile has <code>0600</code> permissions. I also keep an encrypted copy using SOPS and age, with the private key in a separate backup. Do not put a raw <code>oldbooks.k4i</code> in Git just because the repository is private. Private repositories leak too.</p>
<p>The EPUBs follow the same strategy I use for other important files: a local copy, NAS, and off-site backup. I explained this paranoia in <a href="/2023/10/19/akitando-146-protegendo-e-recuperando-dados-perdidos-git-backup-btrfs/">Protecting and Recovering Lost Data</a> and showed the same philosophy applied to movies in <a href="/en/2024/04/03/my-personal-netflix-with-docker-compose/">My Personal Netflix</a>.</p>
<p>Do not delete files from the Kindle or the VM the minute conversion finishes. Open the EPUBs and check the cover, table of contents, images, notes, and a few pages. A backup you&rsquo;ve never tested is just wishful thinking.</p>
<h2>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Amazon has remotely deleted books, publishers update covers and content, old apps stop working, and formats change. The end of Download &amp; Transfer via USB proved that a feature available for eighteen years can disappear with one line in a notice.</p>
<p>The classic example is still unbelievable: in 2009, Amazon deleted <code>1984</code> and <code>Animal Farm</code> by George Orwell from customers&rsquo; Kindles. Later, revisions to Roald Dahl, R.L. Stine, and Agatha Christie were pushed into digital copies people had already bought. The <a href="https://www.vice.com/en/article/amazon-is-killing-your-ability-to-download-kindle-books-next-week/"target="_blank" rel="noopener">Vice article</a> summarizes those cases. Dammit Jeff makes the same point often: even the original cover you chose can turn into an ugly poster for the streaming adaptation because the publisher and store decided to update your &ldquo;purchase.&rdquo;</p>
<p>It doesn&rsquo;t matter whether the next change is censorship, a legitimate correction, another horrible Netflix adaptation cover, or a plain bug. I bought an edition. I want to preserve the edition I bought.</p>
<p>DRM does not stop piracy. A popular book lands on torrents the day it comes out. DRM only gets in the paying customer&rsquo;s way, makes accessibility harder, locks up perfectly good hardware, and turns a purchase into an indefinite rental.</p>
<p>Calibre, DeDRM, KFX Input, and a disposable VM gave me my library back. I can now put those EPUBs on the Xteink, a Kobo, a tablet, my phone, or a reader that doesn&rsquo;t even exist yet. I can switch operating systems and turn off the internet. The files stay with me.</p>
<p>If it isn&rsquo;t on your machine, it isn&rsquo;t yours.</p>
]]></content:encoded><category>storage-and-backup</category><category>linux</category><category>open-source</category></item><item><title>Using AI to Solve My Little Day-to-Day Problems</title><link>https://akitaonrails.github.io/en/2026/07/12/using-ai-to-solve-my-little-day-to-day-problems/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/07/12/using-ai-to-solve-my-little-day-to-day-problems/</guid><pubDate>Sun, 12 Jul 2026 11:00:00 -0300</pubDate><description>&lt;p&gt;I wasn&amp;rsquo;t going to write an article for every little open source project I make. Most of them solve a very specific little problem in MY day-to-day, and a dedicated article would be out of proportion. But the little projects kept piling up, and looking back I realized there are already several that never showed up here. So I decided to do it differently: a single article, mentioning most of them at once.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I wasn&rsquo;t going to write an article for every little open source project I make. Most of them solve a very specific little problem in MY day-to-day, and a dedicated article would be out of proportion. But the little projects kept piling up, and looking back I realized there are already several that never showed up here. So I decided to do it differently: a single article, mentioning most of them at once.</p>
<p>The pattern repeats in all of them: I run into a small friction in daily life, the kind we normally swallow because fixing it would cost an entire weekend, and instead of swallowing it I open an AI agent and fix it. The cost of turning irritation into tooling dropped so much that the math flipped. Today it&rsquo;s worth fixing almost everything.</p>
<p>Everything below is on <a href="https://github.com/akitaonrails"target="_blank" rel="noopener">my GitHub</a>, with binaries, releases and install instructions.</p>
<p>In this post: <a href="#clock-tui-a-desk-clock-that-became-a-panel">clock-tui</a> (with the <a href="#clock-tui-a-desk-clock-that-became-a-panel">google-calendar-tui</a> and <a href="#clock-tui-a-desk-clock-that-became-a-panel">ghpending</a> widgets), <a href="#github-visualize-useless-but-pretty">github-visualize</a>, <a href="#frank-geary-email-the-way-i-wanted-it">frank_geary</a>, <a href="#japanese-manga-frankyomik-frank-manga-and-frank-scanlation">frank_scanlation</a>, <a href="#frank-lyrics-memorizing-songs-line-by-line">frank_lyrics</a>, <a href="#frank-type-typing-practice-with-actual-prose">frank_type</a>, <a href="#distrobox-gaming-a-library-of-how-to-install-games-on-linux">distrobox-gaming</a> and <a href="#aitrepreneur-docker-comfyui-without-dirtying-the-system">aitrepreneur-docker</a>.</p>
<h2>clock-tui: a desk clock that became a panel<span class="hx:absolute hx:-mt-20" id="clock-tui-a-desk-clock-that-became-a-panel"></span>
    <a href="#clock-tui-a-desk-clock-that-became-a-panel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The use case is simple: I have a secondary vertical monitor, and I wanted something more useful there than a wallpaper, something I could just glance at and get relevant information. But it all started because I just wanted a desk clock. I found a little old open source terminal clock program, the original clock-tui, which had been paused for ages, and decided to fork it and continue the work: <a href="https://github.com/akitaonrails/clock-tui"target="_blank" rel="noopener">clock-tui</a>.</p>
<p>I made it prettier, modernized the Rust dependencies, and the most important change: I added support for <strong>command widgets</strong>. The clock sits at the top and below it come panels that run any command that prints text, each with its own refresh. Two widgets I built for it myself:</p>
<ul>
<li><a href="https://github.com/akitaonrails/google-calendar-tui"target="_blank" rel="noopener">google-calendar-tui</a>: a read-only Google Calendar agenda in the terminal, using the accounts already in GNOME Online Accounts (zero OAuth setup). One glance and I know my appointments for the day.</li>
<li><a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a>: lists open issues and pull requests across all the repositories I care about. Now that I have dozens of open source projects, this is how I notice within seconds when a new PR or issue arrives, without opening GitHub.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/ghpending.webp" alt="ghpending widget showing open pull requests and issues across several repositories at once."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/google-calendar-tui.webp" alt="google-calendar-tui’s colored agenda printed straight to the terminal."  loading="lazy" /></p>
<p>And today I spent the day adding theme support, because someone on X commented that the look could be made to resemble Evangelion. Challenge accepted: there&rsquo;s now an <code>evangelion</code> theme (purple and lavender) and a <code>nerv</code> theme (red, amber and green, inspired by the show&rsquo;s alert screens), switching at runtime with <code>Shift+T</code>. The theme is injected into the widgets via an environment variable, so the panels follow the palette.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/clock-tui-nerv.webp" alt="clock-tui with the NERV theme: digital clock in red with system health, calendar and GitHub widgets in amber and green."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/clock-tui-evangelion.webp" alt="clock-tui with the Evangelion theme: the same screen in the purple and lavender palette of EVA-01."  loading="lazy" /></p>
<p>Installing on Arch: <code>yay -S clock-tui-bin</code>. The widgets: <code>yay -S ghpending-bin</code> (there&rsquo;s also <code>brew install</code> via <code>akitaonrails/tap</code> on macOS) and <code>yay -S google-calendar-tui-bin</code>. All of them have prebuilt binaries on GitHub Releases for those not on Arch.</p>
<h2>github-visualize: useless, but pretty<span class="hx:absolute hx:-mt-20" id="github-visualize-useless-but-pretty"></span>
    <a href="#github-visualize-useless-but-pretty" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This one was born because of Jarred Sumner&rsquo;s article about rewriting Bun&rsquo;s TypeScript in Rust, which I <a href="/en/2026/07/09/the-bun-in-rust-response-andrew-kelly-should-have-written/">posted about recently</a>. I don&rsquo;t know which tool he used to illustrate the post, but I really liked the chart animations. Is it useless? It is. But it&rsquo;s pretty, and pretty is reason enough to make a copy.</p>
<p><a href="https://github.com/akitaonrails/github-visualize"target="_blank" rel="noopener">github-visualize</a> is a self-hosted dashboard that monitors my GitHub repositories and replays their progress with animated visualizations: a commit timeline with lines added and deleted on a log scale, a commit heat map by day and hour, a CI race to green. Now I can add any repository of mine and get pretty visualizations of productivity, activity, commits and builds. Maybe I&rsquo;ll use it in presentation slides, or to illustrate future posts here on the blog.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/github-visualize-timeline.webp" alt="Animated commit timeline replay in github-visualize: lines added in pink and deleted in cyan, with animated counters and a git log feed."  loading="lazy" /></p>
<p>Install: public image on Docker Hub as <a href="https://hub.docker.com/r/akitaonrails/github-visualize"target="_blank" rel="noopener"><code>akitaonrails/github-visualize</code></a>, single container with SQLite in a volume, no external database or Redis.</p>
<h2>Frank Geary: email the way I wanted it<span class="hx:absolute hx:-mt-20" id="frank-geary-email-the-way-i-wanted-it"></span>
    <a href="#frank-geary-email-the-way-i-wanted-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I decided to use GNOME&rsquo;s Geary as my main email client. It&rsquo;s the closest to the interface of Apple&rsquo;s default Mail app: clean, direct, no ceremony. I know, there&rsquo;s Thunderbird, but I find it bloated and very ugly. There&rsquo;s Mailspring, which I find bloated and heavy. My email flow is short: sweep the inbox, tag, archive and reply. Nothing else.</p>
<p>Geary is almost perfect, but it had two big problems for me. First: on my vertical monitor there&rsquo;s much less horizontal space, and Geary has 3 fixed columns. The first column, which only lists accounts and folders/tags, I don&rsquo;t need to see all the time, but there was no way to collapse it.</p>
<p>Second, and worse: the composer&rsquo;s recipient field in practice never autocompleted anything (Geary does have the mechanism, but with a contact visibility filter so restrictive it never suggested anyone). I had to type the address by hand or copy and paste from another email. In 2026.</p>
<p>My first solution was two external GTK modules injected into Geary, one for each problem (both obsolete now). They worked, but they required installing Geary compiled from source, and on every <code>yay -Syu</code> there it went recompiling everything again.</p>
<p>I got tired and did what I should have done from the start: I forked Geary and created <a href="https://github.com/akitaonrails/frank_geary"target="_blank" rel="noopener">Frank Geary</a>, which adds both features straight into the code. The sidebar now collapses, and the recipient autocompletes by consulting the contacts from your existing emails. I&rsquo;ll keep maintaining the fork by rebasing from upstream frequently.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-geary-autocomplete.webp" alt="Frank Geary’s recipient autocomplete popup in the composer, suggesting contacts as you type."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-geary-sidebar.webp" alt="Frank Geary with the accounts sidebar collapsed: just the conversation list and the reading pane, perfect for a vertical monitor."  loading="lazy" /></p>
<p>And the best part: there&rsquo;s now a package on the AUR, so installing goes like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">yay -S frank-geary-bin    <span class="c1"># prebuilt binary (x86_64), from the GitHub release</span>
</span></span><span class="line"><span class="cl">yay -S frank-geary        <span class="c1"># or compiling from source</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Both packages replace the system&rsquo;s <code>geary</code> (they provide/conflict with it), so the swap is clean and updates arrive like any other package. One detail after installing or upgrading: when the watch-for-new-mail option is on, Geary keeps running in the background as a D-Bus service, so run a <code>geary --quit</code> to make sure no old process is left hanging around.</p>
<h2>Japanese manga: FrankYomik, FRANK MANGA+ and FRANK Scanlation<span class="hx:absolute hx:-mt-20" id="japanese-manga-frankyomik-frank-manga-and-frank-scanlation"></span>
    <a href="#japanese-manga-frankyomik-frank-manga-and-frank-scanlation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Anyone following the blog knows about my love for Japanese manga. I already <a href="/en/2026/03/05/my-first-vibe-code-failure-frank-yomik/">posted about FrankYomik</a>, which was born so I could read the original Japanese manga I buy from Amazon Japan.</p>
<p>The problem: manga aimed at adult audiences (no, not porn! I&rsquo;m talking about subjects like business or military topics) doesn&rsquo;t have &ldquo;furigana&rdquo;, the little kana subtitles printed next to difficult kanji, indicating the reading. Shounen manga has furigana on everything, so you can read it with student-level vocabulary. The adult ones assume you already know how to read the rare kanji. I don&rsquo;t.</p>
<p><a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener">FrankYomik</a> solves that by adding furigana on top of the page, in real time: a model detects the speech bubbles, manga-ocr extracts the text, and the furigana (or a full translation, via a local LLM on Ollama) is rendered on top, all running on my own hardware. And the important detail: on-the-fly, over the image I already have legitimately open, without downloading or redistributing a single page, so no copyright or license infringement.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-yomik-furigana.webp" alt="FrankYomik automatically adding furigana over the difficult kanji on a Japanese manga page."  loading="lazy" /></p>
<p>Then came <a href="https://github.com/akitaonrails/frank_mangaplus"target="_blank" rel="noopener">FRANK MANGA+</a>, which I <a href="/en/2026/05/30/manga-plus-shueisha-on-the-desktop-frank-manga-plus/">also posted about</a>. I pay for the subscription to Manga Plus, Shueisha&rsquo;s official app, but it only lets me read on mobile (Android/iOS). On a small tablet it&rsquo;s tolerable, but I have a 32&quot; Samsung Odyssey OLED monitor sitting right in front of me.</p>
<p>I figured out how to use my own subscription outside the app and built a desktop reader in Tauri: it runs on Linux, macOS and Windows, the free tier works out of the box and subscribers paste their own secret to unlock the premium chapters.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-mangaplus-library.webp" alt="FRANK MANGA&#43;’s library on the desktop: a grid of Shueisha manga covers with full catalog search."  loading="lazy" /></p>
<p>Install: AppImage, <code>.deb</code> and <code>.dmg</code> on the <a href="https://github.com/akitaonrails/frank_mangaplus/releases/latest"target="_blank" rel="noopener">releases</a>, or <code>yay -S mangaplus-reader-bin</code> on Arch.</p>
<p>And finally, I also read the occasional community &ldquo;scanlations&rdquo;: fans scan the pages of the original Japanese manga and translate them (nowadays most use AI in the process, there are even models trained to recognize speech bubbles, and I used one of those in FrankYomik itself). These scanlations are spread across several different websites, like MangaDex.</p>
<p>First I made a Chrome extension to prettify those sites (obsolete now), but I got tired of living with dozens of tabs in Brave just for scanlation sites. So I built <a href="https://github.com/akitaonrails/frank_scanlation"target="_blank" rel="noopener">FRANK Scanlation</a>, along the same lines as FRANK MANGA+: a desktop app that concentrates all my favorite scanlations in one place, with a library, per-title reading progress and checking for new chapters.</p>
<p>The reading windows load the site itself and inject a decent reader on top, with double-page spreads and keyboard navigation. Nothing is hardcoded to any website: they&rsquo;re heuristics that detect image sequences and chapter numbering in any URL. It became my preferred way to read the manga that can&rsquo;t be bought on Amazon or from Shueisha.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-scanlation-library.webp" alt="FRANK Scanlation’s library: cards with covers, reading progress and a button to continue where you left off."  loading="lazy" /></p>
<p>Install: AppImage, <code>.deb</code> and <code>.rpm</code> (and a macOS build) on the <a href="https://github.com/akitaonrails/frank_scanlation/releases"target="_blank" rel="noopener">GitHub releases</a>.</p>
<h2>Frank Lyrics: memorizing songs line by line<span class="hx:absolute hx:-mt-20" id="frank-lyrics-memorizing-songs-line-by-line"></span>
    <a href="#frank-lyrics-memorizing-songs-line-by-line" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I already <a href="/en/2026/04/05/turning-youtube-into-a-karaoke-app-frank-karaoke/">posted about Frank Karaoke</a>, a little app to add scoring on top of YouTube and enjoy karaoke with family and friends. But there&rsquo;s a sibling use case: I like learning new songs (a new anime opening, for example), and the process of memorizing lyrics is repeating the SAME line several times. In the YouTube player that&rsquo;s hell: you keep hunting by hand for the exact spot on the timeline to go back to, miss it by two seconds, rewind too much, overshoot.</p>
<p>To solve that I created <a href="https://github.com/akitaonrails/frank_lyrics"target="_blank" rel="noopener">Frank Lyrics</a>, a simple Chrome extension that figures out the correct timing for each line of the lyrics using the public markers from <a href="https://lrclib.net/"target="_blank" rel="noopener">LRCLIB</a> and injects controls into the YouTube page itself. LRCLIB, for those who don&rsquo;t know it, is an open, community-driven library of synchronized lyrics: each line comes with a timestamp (the classic LRC format from music players), with a public API, free and keyless.</p>
<p>The extension matches those timestamps to the video and gives me buttons to repeat the exact line I&rsquo;m memorizing, as many times as I need, without hunting the timeline. If you enjoy karaoke, the Frank Karaoke + Frank Lyrics combo should serve you well.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-lyrics.webp" alt="Frank Lyrics’ panel over a lyric video on YouTube: each line of the lyrics with its timestamp and controls to repeat the current line."  loading="lazy" /></p>
<p>Install: download the <code>.zip</code> from the <a href="https://github.com/akitaonrails/frank_lyrics/releases"target="_blank" rel="noopener">releases</a>, unzip it, open <code>chrome://extensions</code>, enable developer mode and &ldquo;Load unpacked&rdquo; pointing at the folder.</p>
<h2>Frank Type: typing practice with actual prose<span class="hx:absolute hx:-mt-20" id="frank-type-typing-practice-with-actual-prose"></span>
    <a href="#frank-type-typing-practice-with-actual-prose" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Anyone who has followed me for a while knows I love my keyboards. There are videos on the Akitando channel about it and <a href="/2024/10/24/meus-teclados-modernos-favoritos/">posts here on the blog about my favorite keyboards</a>. And from time to time I like to train on MonkeyType. But I dislike typing random words. TypeRacer solves that by using real public texts, except it makes me wait for other players in the room (I hate multiplayer games). In other words: I wanted a single player experience, with real prose, but with the MonkeyType aesthetic, which I prefer.</p>
<p>So I created <a href="https://github.com/akitaonrails/frank_type"target="_blank" rel="noopener">Frank Type</a>, a mini-clone of both: a typing trainer in Rails 8 that uses normalized public-domain prose excerpts instead of random word lists. It&rsquo;s local-first and account-free: session history, timing data and profile charts stay in the browser&rsquo;s local storage. It even has a digraph heat map to show which key combinations slow you down.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/frank-type.webp" alt="Frank Type’s practice screen: public-domain text to type, with statistics and a digraph heat map, in the MonkeyType aesthetic."  loading="lazy" /></p>
<p>Install: it&rsquo;s a Docker container published as <code>akitaonrails/frank_type</code>. One command brings it up at <code>http://localhost:3200</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://raw.githubusercontent.com/akitaonrails/frank_type/master/bin/docker-run.sh <span class="p">|</span> bash</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>distrobox-gaming: a library of how to install games on Linux<span class="hx:absolute hx:-mt-20" id="distrobox-gaming-a-library-of-how-to-install-games-on-linux"></span>
    <a href="#distrobox-gaming-a-library-of-how-to-install-games-on-linux" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I game on the same PC I work on, but I refuse to mix emulator packages and Wine hackery with my development environment. The solution was to isolate gaming entirely inside a <a href="https://github.com/89luca89/distrobox"target="_blank" rel="noopener">distrobox</a> (containers that integrate with your desktop as if they were native), and <a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">distrobox-gaming</a> is the repository of Ansible playbooks that builds that Arch box from scratch: ES-DE as the frontend, standalone emulators, RetroArch cores, per-game configs. My Arch/Omarchy host stays clean.</p>
<p>The rule I imposed on myself: every new game I install has to become a reproducible Ansible recipe. I confess I haven&rsquo;t tested the full rebuild from scratch yet, but that&rsquo;s the idea: any trick or hack required gets documented in code instead of lost in shell history.</p>
<p>And there&rsquo;s no shortage of tricks, because I&rsquo;ve been installing old abandonware: the Colin McRae Rally series (from the PS1 version with a 60 fps patch up to 2007&rsquo;s DiRT), Sega Rally Revo, OutRun 2006 Coast 2 Coast, among others. Each with its own Wine quirks, patches and configs. Without meaning to, the repository is becoming a library of documentation on how to install games, emulators and retro games on Linux.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/07/12/probleminhas/distrobox-gaming-cmr04.webp" alt="Colin McRae Rally 04 running in the gaming box: the Service Area screen with the Mitsubishi Lancer Evolution before the next stage."  loading="lazy" /></p>
<p>Along the same lines there&rsquo;s <a href="https://github.com/akitaonrails/distrobox-llm"target="_blank" rel="noopener">distrobox-llm</a>, which does the same isolation for my local LLM environment (CUDA, Ollama, LM Studio and friends), leaving only the NVIDIA driver on the host.</p>
<p>Install: clone the repository and run the playbooks:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">cd</span> ansible
</span></span><span class="line"><span class="cl">ansible-galaxy collection install -r collections/requirements.yml
</span></span><span class="line"><span class="cl">cp host_vars/localhost.yml.example host_vars/localhost.yml
</span></span><span class="line"><span class="cl"><span class="nv">$EDITOR</span> host_vars/localhost.yml
</span></span><span class="line"><span class="cl">ansible-playbook site.yml</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>aitrepreneur-docker: ComfyUI without dirtying the system<span class="hx:absolute hx:-mt-20" id="aitrepreneur-docker-comfyui-without-dirtying-the-system"></span>
    <a href="#aitrepreneur-docker-comfyui-without-dirtying-the-system" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For image generation I like ComfyUI, and I <a href="/en/2025/04/20/understanding-the-basics-of-comfyui-to-generate-ai-images/">posted about it last year</a>. I follow a youtuber called <a href="https://www.youtube.com/@Aitrepreneur"target="_blank" rel="noopener">Aitrepreneur</a> who maintains a Patreon page with recipes to install and configure ComfyUI with the newest models and workflows. His curation work is great, but the recipes are old school <code>.sh</code> scripts, meant to run as one-shots on a RunPod instance, for example.</p>
<p>Now that LLMs evolved to the point of writing decent Dockerfiles, I created <a href="https://github.com/akitaonrails/aitrepreneur-docker"target="_blank" rel="noopener">aitrepreneur-docker</a>, which converts those scripts into proper Docker images and containers: pinned versions, persistent data on the host or NAS, one command to bring up or upgrade each app. That way I run everything isolated on my machine, without littering my Linux with tons of Python packages and hacks that could destabilize the system.</p>
<p>Two important notices. The credit for the stack selection, model curation and workflows all goes to Aitrepreneur: the repository only translates his work into Docker form, and his original scripts are paid Patreon content that is NOT included.</p>
<p>If you find it useful, <a href="https://www.patreon.com/c/aitrepreneur/home"target="_blank" rel="noopener">subscribe to his Patreon</a> to contribute to his content creation (that&rsquo;s also where you get the original files). And the repository doesn&rsquo;t cover everything he has produced, only the most recent recipes.</p>
<p>Install: <code>git clone</code>, <code>make setup</code> (creates the <code>.env</code> for you to put your Hugging Face token), <code>make build</code> and <code>make up</code>.</p>
<h2>And there&rsquo;s more where these came from<span class="hx:absolute hx:-mt-20" id="and-theres-more-where-these-came-from"></span>
    <a href="#and-theres-more-where-these-came-from" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you&rsquo;re new here: this is just the batch that hadn&rsquo;t shown up on the blog yet. There are plenty more projects I&rsquo;ve covered in dedicated posts. <a href="/en/2026/06/16/ai-memory-long-term-memory-karpathy-wiki-self-improvement-hermes-projects/">ai-memory</a> is the most popular, most used and most contributed-to of all. <a href="/en/2026/05/24/akita-ai-tips-toolkit-ai-jail-ai-memory-ai-usagebar/">ai-jail</a>, which showed up again in <a href="/en/2026/07/11/how-to-protect-yourself-from-agents-deleting-your-stuff/">yesterday&rsquo;s post about destructive agents</a>, was the first of the series and is the second most popular.</p>
<p>And there are the others in the Frank series (&ldquo;Frank&rdquo; in honor of Frank Rosenblatt, creator of the perceptron, the original neural network; the name marks the experimental projects I do for fun):</p>
<ul>
<li><a href="/en/2026/02/23/vibe-code-built-a-smart-image-indexer-with-ai-in-2-days-frank-sherlock/">Frank Sherlock</a>: smart image indexer</li>
<li><a href="/en/2026/02/21/vibe-code-built-a-mega-clone-in-rails-in-1-day-frankmega/">Frank Mega</a>: MEGA clone for my home server</li>
<li><a href="/en/2026/02/01/frankmd-markdown-editor-vibe-code-part-1/">FrankMD</a>: markdown editor</li>
<li><a href="/en/2026/03/09/going-after-email-fraud-frank-fbi/">Frank FBI</a>: email fraud analyzer</li>
<li><a href="/en/2026/03/27/teaching-people-to-question-the-news-frank-investigator/">Frank Investigator</a>: teaches you to question the news</li>
</ul>
<p>Everything is open source and on <a href="https://github.com/akitaonrails"target="_blank" rel="noopener">my GitHub</a>. Everybody is welcome to contribute with issues, pull requests, or just by sharing with your friends. Each of these projects was born from a real little problem of mine. Maybe one of them solves yours too.</p>
]]></content:encoded><category>vibe-coding</category><category>open-source</category><category>artificial-intelligence</category></item><item><title>The Rio 3.5 LLM Controversy. Plagiarism?</title><link>https://akitaonrails.github.io/en/2026/06/15/rio-3-5-llm-controversy-plagiarism/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/06/15/rio-3-5-llm-controversy-plagiarism/</guid><pubDate>Mon, 15 Jun 2026 16:00:00 -0300</pubDate><description>&lt;figure&gt;
&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/15/rio-3-5/rio35.png" alt="Scooby-Doo meme unmasking Rio-3.5-Open-397B and revealing Nex-N2-Pro" /&gt;
&lt;figcaption&gt;The meme is funny because it summarizes the accusation. But let's separate the joke, the technical evidence, and the license question.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This week a curious controversy showed up in the open LLM world: &lt;strong&gt;&lt;a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B"target="_blank" rel="noopener"&gt;Rio 3.5 Open 397B&lt;/a&gt;&lt;/strong&gt;, presented by the &lt;a href="https://prefeitura.rio/cidade/prefeitura-do-rio-anuncia-projetos-de-inovacao-que-serao-testados-na-cidade/"target="_blank" rel="noopener"&gt;City of Rio / IplanRIO in the Rio 3 Open announcement&lt;/a&gt; as an open model.&lt;/p&gt;
&lt;p&gt;The accusation: in practice, the published checkpoint, meaning the model weights file, was a direct blend of &lt;strong&gt;&lt;a href="https://huggingface.co/nex-agi/Nex-N2-Pro"target="_blank" rel="noopener"&gt;Nex-N2-Pro&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://huggingface.co/Qwen/Qwen3.5-397B-A17B"target="_blank" rel="noopener"&gt;Qwen3.5-397B-A17B&lt;/a&gt;&lt;/strong&gt;, without initial credit to Nex.&lt;/p&gt;</description><content:encoded><![CDATA[<figure>
  <img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/15/rio-3-5/rio35.png" alt="Scooby-Doo meme unmasking Rio-3.5-Open-397B and revealing Nex-N2-Pro" />
  <figcaption>The meme is funny because it summarizes the accusation. But let's separate the joke, the technical evidence, and the license question.</figcaption>
</figure>
<p>This week a curious controversy showed up in the open LLM world: <strong><a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B"target="_blank" rel="noopener">Rio 3.5 Open 397B</a></strong>, presented by the <a href="https://prefeitura.rio/cidade/prefeitura-do-rio-anuncia-projetos-de-inovacao-que-serao-testados-na-cidade/"target="_blank" rel="noopener">City of Rio / IplanRIO in the Rio 3 Open announcement</a> as an open model.</p>
<p>The accusation: in practice, the published checkpoint, meaning the model weights file, was a direct blend of <strong><a href="https://huggingface.co/nex-agi/Nex-N2-Pro"target="_blank" rel="noopener">Nex-N2-Pro</a></strong> and <strong><a href="https://huggingface.co/Qwen/Qwen3.5-397B-A17B"target="_blank" rel="noopener">Qwen3.5-397B-A17B</a></strong>, without initial credit to Nex.</p>
<p>The question mark in the title is intentional. &ldquo;Plagiarism&rdquo; is a loaded word, especially when we&rsquo;re talking about a model under a permissive license. The right question isn&rsquo;t only &ldquo;can they use it?&rdquo; In open source, most of the time they can. The question is: <strong>did they use it, modify it, redistribute it, and give proper credit?</strong> And for an AI model, there&rsquo;s another question just as important: <strong>were they transparent about what was actually done?</strong></p>
<p>My short conclusion before the long version: Nex&rsquo;s public evidence is strong. Strong enough to say the initially published Rio 3.5 checkpoint looks like an almost linear blend of Nex-N2-Pro and Qwen3.5-397B-A17B.</p>
<p>Rio&rsquo;s own <a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B/raw/main/README.md"target="_blank" rel="noopener">README</a> was changed after the <a href="https://github.com/nex-agi/Nex-N2/issues/4"target="_blank" rel="noopener">Nex issue</a> to acknowledge Nex + Qwen and say there had been an &ldquo;incorrect upload&rdquo;.</p>
<p>I did not reproduce the tensor-by-tensor analysis myself. I&rsquo;m evaluating the evidence Nex published, the public Hugging Face history, and the tests I ran separately in my own benchmark.</p>
<p>This does not prove, legally, &ldquo;plagiarism&rdquo; in the classic sense. But it shows a serious attribution and communication failure. And for a public-sector project, with a city government involved, that matters more.</p>
<h2>What the City of Rio announced<span class="hx:absolute hx:-mt-20" id="what-the-city-of-rio-announced"></span>
    <a href="#what-the-city-of-rio-announced" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In April, the City published a note saying IplanRio had presented <strong>Rio 3 Open</strong>, &ldquo;a family of six cutting-edge artificial intelligence models, fully free and open.&rdquo;</p>
<p>The official text said the idea was to make Rio recognized as a public innovation hub, capable of developing its own AI solutions &ldquo;without depending on foreign platforms.&rdquo; It also highlighted an MIT license, free use, modification, and even profit from the technology. Source: <a href="https://prefeitura.rio/cidade/prefeitura-do-rio-anuncia-projetos-de-inovacao-que-serao-testados-na-cidade/"target="_blank" rel="noopener">City of Rio, 2026-04-02</a>.</p>
<p>A <a href="https://www.mobiletime.com.br/noticias/02/04/2026/prefeitura-do-rio-3-llms/"target="_blank" rel="noopener">Mobile Time</a> article gave more context: the family would be developed from Qwen, Alibaba&rsquo;s Chinese model.</p>
<p>João Cabaretta, president of IplanRio, reportedly said: &ldquo;What we did was take the Qwen model, already ready, and from it we modified the model.&rdquo; The article also listed expected city use cases: reading security cameras for suspicious activity, analyzing accountability documents, generating institutional images and videos, and citizen service.</p>
<p>So far, nothing absurd. Taking an open model and adapting it for local use is exactly what many people do. If the city managed to assemble infrastructure, adapt a model, document it, and publish weights, good. I&rsquo;m in favor of that. I prefer it over another closed contract with a foreign SaaS nobody can audit.</p>
<p>The problem starts with how Rio 3.5 was presented.</p>
<p>On Hugging Face, the <a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B"target="_blank" rel="noopener"><code>prefeitura-rio/Rio-3.5-Open-397B</code></a> repository initially said the model was &ldquo;developed by IplanRIO&rdquo;, &ldquo;Post-trained from Qwen 3.5 397B&rdquo;, with <strong>MIT License</strong>, and acknowledgments to the Qwen Team and SwiReasoning. That older version is still accessible in the Hugging Face history: <a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B/raw/cd503cdc7aaac2506bf68f6d278503ddb07a83ef/README.md"target="_blank" rel="noopener">README before the correction</a>.</p>
<p>The card also promised a frontier-class general-purpose model, with <strong>397B total / 17B active parameters</strong>, a <strong>1,010,000-token</strong> context window, and commercial/research use under MIT. In other words: this wasn&rsquo;t a footnote. It was an ambitious release.</p>
<p>Notice the detail: Qwen appeared as the base. Nex did not.</p>
<p>And this matters because, in Nex&rsquo;s own discussion, someone corrected the narrative by saying Rio <strong>had credited Qwen</strong> early on. That&rsquo;s true: the <a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B/commit/a0b566a0ecd25ae6996ccafd377b2162af01077a"target="_blank" rel="noopener">second model-card commit</a> already listed <code>base_model: Qwen/Qwen3.5-397B-A17B</code>. A comment in the issue points this out too: <a href="https://github.com/nex-agi/Nex-N2/issues/4#issuecomment-4710338431"target="_blank" rel="noopener">&ldquo;They did say Qwen 3.5 397B was the base model from the beginning&hellip;&rdquo;</a>.</p>
<p>So the stronger accusation isn&rsquo;t &ldquo;they omitted Qwen.&rdquo; It&rsquo;s: <strong>they credited Qwen, but omitted Nex-N2-Pro</strong>, exactly the component Nex&rsquo;s weight analysis says was the majority ingredient in the published recipe.</p>
<p>After Nex opened the issue, the current README said something different:</p>
<blockquote>
  <p>&ldquo;The model was built through a merge of <a href="https://huggingface.co/nex-agi/Nex-N2-Pro"target="_blank" rel="noopener">https://huggingface.co/nex-agi/Nex-N2-Pro</a> and <a href="https://huggingface.co/Qwen/Qwen3.5-397B-A17B"target="_blank" rel="noopener">https://huggingface.co/Qwen/Qwen3.5-397B-A17B</a>, followed by On-Policy Distillation from a stronger model. We detected an incorrect upload in the previous version, where the merged base version was uploaded instead of the final distilled model. We apologize for the confusion.&rdquo;</p>

</blockquote>
<p>Source: <a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B/raw/main/README.md"target="_blank" rel="noopener">current Rio 3.5 README</a>, changed in commit <a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B/commit/a778c1ec4e21180ee55c3ea016a348e549e75f09"target="_blank" rel="noopener">a778c1e</a>.</p>
<p>That sentence changes the story a lot. Before: &ldquo;post-trained from Qwen.&rdquo; After: &ldquo;blend of Nex-N2-Pro and Qwen, followed by distillation, but we uploaded the wrong file.&rdquo;</p>
<p>That may be true. There may really have been a wrong upload. But as an outside observer, I can only analyze what was published.</p>
<h2>Nex&rsquo;s accusation<span class="hx:absolute hx:-mt-20" id="nexs-accusation"></span>
    <a href="#nexs-accusation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Nex opened issue <a href="https://github.com/nex-agi/Nex-N2/issues/4"target="_blank" rel="noopener">nex-agi/Nex-N2#4</a> on June 14. In my translation/summary, the core accusation is direct:</p>
<blockquote>
  <p><code>prefeitura-rio/Rio-3.5-Open-397B</code> is presented as an original 397B model trained by IplanRIO. It is not. Its weights are a direct element-wise blend of our model, Nex, with the official <code>Qwen3.5-397B-A17B</code> base — about 0.6 Nex / 0.4 Qwen — and we find no evidence of their own training.</p>

</blockquote>
<p>Nex points to two lines of evidence.</p>
<p>First: identity behavior. According to them, Rio&rsquo;s service used a built-in system prompt saying &ldquo;You are Rio&rdquo;. With that prompt removed, they asked 120 identity questions. The reported result was:</p>
<ul>
<li>&ldquo;Nex&rdquo;: 95/120, or 79.2%.</li>
<li>&ldquo;Nex-AGI&rdquo;: 88/120, or 73.3%.</li>
<li>&ldquo;Rio&rdquo;: 0/120.</li>
</ul>
<p>Example response cited by Nex:</p>
<blockquote>
  <p>&ldquo;I am Nex, from Nex-AGI. Nex-AGI is a large-model ecosystem alliance, jointly built by the Shanghai Innovation Institute…&rdquo;</p>

</blockquote>
<p>Source: <a href="https://github.com/nex-agi/Nex-N2/issues/4#issuecomment-4702171801"target="_blank" rel="noopener">Nex comment on identity behavior</a>.</p>
<p>That alone doesn&rsquo;t prove everything. A model identifying as another model can happen because of dataset contamination, system prompt, a bad test prompt, or reused fine-tuning. But it&rsquo;s a bad sign when a supposedly &ldquo;Rio&rdquo; model never says &ldquo;Rio&rdquo; without the mask and says &ldquo;Nex&rdquo; very often.</p>
<p>The second piece of evidence is more serious: weight analysis.</p>
<p>Nex&rsquo;s hypothesis is simple. If Rio = α·Nex + (1−α)·Qwen, then for every tensor:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">(Rio − Qwen) ≈ α · (Nex − Qwen)</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>They report very consistent values: routed experts with α ≈ 0.571 ± 0.0016 and <code>cos_fit</code> 0.993; <code>lm_head</code> with 0.574 and 0.991; attention around 0.585 and 0.986; linear-attention projections around 0.586 and 0.984. Source: <a href="https://github.com/nex-agi/Nex-N2/issues/4#issuecomment-4702181710"target="_blank" rel="noopener">Nex comment on weight analysis</a>.</p>
<p>This is the part that carries the most weight. High similarity between models in the same family would not be surprising. But tensor-by-tensor collinearity at this level is a different thing. If the equation reproduces across all tensors, it doesn&rsquo;t look like &ldquo;we trained something similar.&rdquo; It looks like a merge.</p>
<p>The weak point: until someone reproduces it independently, this is still an analysis presented by an interested party. The strong point: it&rsquo;s falsifiable technical analysis, not just a screenshot of a chat.</p>
<h2>Nex&rsquo;s tweet<span class="hx:absolute hx:-mt-20" id="nexs-tweet"></span>
    <a href="#nexs-tweet" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><figure>
  <img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/15/rio-3-5/nex-tweet-rio35.png" alt="Screenshot of Nex's tweet saying Rio 3.5 is essentially Nex N2 Pro wearing a different hat" />
  <figcaption>Screenshot of Nex's tweet. Original link: <a href="https://x.com/NexEcosystem/status/2066180407100571714">x.com/NexEcosystem/status/2066180407100571714</a>.</figcaption>
</figure>
<p>Nex&rsquo;s tweet summarizes the accusation in meme form:</p>
<blockquote>
  <p>&ldquo;The Rio 3.5 model broke the internet this week. The plot twist? It&rsquo;s essentially our open-source model, Nex N2 Pro, wearing a different hat.&rdquo;</p>

</blockquote>
<p>And continues:</p>
<blockquote>
  <p>&ldquo;We analyzed the weights, and the recipe is exact: Rio 3.5 ≈ 0.6 * Nex N2 Pro + 0.4 * Qwen 3.5&rdquo;</p>

</blockquote>
<p>It also repeats the identity claim:</p>
<blockquote>
  <p>&ldquo;It even literally introduces itself as &lsquo;Nex N2 Pro&rsquo; if you ask it without initial system prompt!&rdquo;</p>

</blockquote>
<p>And closes with the most important sentence:</p>
<blockquote>
  <p>&ldquo;But in the open-source world, attribution matters.&rdquo;</p>

</blockquote>
<p>That&rsquo;s it. The most important part isn&rsquo;t &ldquo;they used our model.&rdquo; Open models exist to be used. If the analysis is correct, the complaint is: they allegedly used it, benefited from inherited performance, announced results, but only gave credit after Nex exposed the blend.</p>
<h2>But what is Nex-N2-Pro?<span class="hx:absolute hx:-mt-20" id="but-what-is-nex-n2-pro"></span>
    <a href="#but-what-is-nex-n2-pro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before going further, it&rsquo;s worth explaining who Nex is in this story, because it didn&rsquo;t come out of nowhere either.</p>
<p>In the <a href="https://huggingface.co/nex-agi/Nex-N2-Pro/raw/main/README.md"target="_blank" rel="noopener">official model card</a>, Nex describes <strong>Nex-N2</strong> as &ldquo;an agentic model with Agentic Thinking&rdquo;.</p>
<p>Marketing aside, the promise is clear: not just a good chat model, but a model tuned for long agent tasks. Coding, tool calls, terminal execution. The annoying kind of workflow where the model needs to plan, execute, see environmental feedback, fix things, and iterate.</p>
<p>And yes: it is also based on Qwen. The card itself says the two models in the family were post-trained on top of the Qwen3.5 series:</p>
<ul>
<li><strong>Nex-N2-Pro</strong>: built on <a href="https://huggingface.co/Qwen/Qwen3.5-397B-A17B"target="_blank" rel="noopener"><code>Qwen3.5-397B-A17B</code></a>.</li>
<li><strong>Nex-N2-mini</strong>: built on <a href="https://huggingface.co/Qwen/Qwen3.5-35B-A3B-Base"target="_blank" rel="noopener"><code>Qwen3.5-35B-A3B-Base</code></a>.</li>
</ul>
<p>So Nex is not saying &ldquo;we created a base architecture from scratch.&rdquo; It is saying: we took Qwen as a base and did agent-focused post-training on top. The promised difference is in that post-training.</p>
<p>They call the framework <strong>Agentic Thinking</strong>, split into two ideas:</p>
<ul>
<li><strong>Adaptive Thinking</strong>: the model decides when to think less and act quickly, or when to spend more reasoning on critical decisions.</li>
<li><strong>Coherent Thinking</strong>: keeping one consistent reasoning paradigm across general tasks, coding, and agent tasks, instead of treating reasoning, tool use, and execution as separate islands.</li>
</ul>
<p>There are practical details too: they recommend a customized fork of <code>sglang</code>, use <code>reasoning-parser qwen3</code>, <code>tool-call-parser qwen3_coder</code>, talk about robust function calling, and list agent/coding benchmarks where Nex-N2-Pro would land close to proprietary models like GPT-5.5 and Opus 4.7.</p>
<p>Of course, vendor benchmarks always need salt. But the thesis is this: <strong>raw Qwen is the base; Nex is the agent post-training and packaging that should turn that base into a better model for real agent work</strong>.</p>
<p>That matches my independent benchmark. Qwen3.5-397B-A17B base did badly: 42/C. Nex-N2-Pro did well: 83/A. Same base, brutal difference. At least in my Rails/RubyLLM test, Nex&rsquo;s value doesn&rsquo;t seem to be &ldquo;it has 397B parameters.&rdquo; Qwen already had that. The value is in fixing agent behavior the Qwen base did not have: using a real API, finishing the task, validating the environment, handling errors.</p>
<p>That distinction matters for the Rio controversy. If Rio 3.5 used Nex as the main ingredient, it&rsquo;s not just &ldquo;Qwen under another name.&rdquo; It would have used precisely the part that made Qwen useful for agent tasks. And that part was Nex&rsquo;s work.</p>
<h2>What Rio effectively answered<span class="hx:absolute hx:-mt-20" id="what-rio-effectively-answered"></span>
    <a href="#what-rio-effectively-answered" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The most concrete public answer I could verify was the README change on Hugging Face. Rio now says:</p>
<ol>
<li>The model is built through a merge of Nex-N2-Pro and Qwen3.5-397B-A17B.</li>
<li>After that there would be an <strong>On-Policy Distillation</strong> step from a stronger model.</li>
<li>The initially uploaded checkpoint was the &ldquo;merged base version&rdquo;, not the final distilled model.</li>
<li>They were working to reupload the correct model.</li>
</ol>
<p>The Hugging Face commit history also shows that, after the issue, many files from <code>model-00001.safetensors</code> through <code>model-00097.safetensors</code> and a benchmark image were removed. You can see it through the <a href="https://huggingface.co/api/models/prefeitura-rio/Rio-3.5-Open-397B/commits/main"target="_blank" rel="noopener">Hugging Face commits API</a>.</p>
<p>Here comes my normal engineer skepticism. &ldquo;We uploaded the wrong file&rdquo; is a possible explanation. It happens. But when the wrong file, according to Nex&rsquo;s analysis, is exactly a mathematical combination of upstream models with no initial credit, and the correction arrives an hour after the accusation, it&rsquo;s hard to call it a mere operational detail.</p>
<p>Not impossible. Hard.</p>
<h2>What model merging is<span class="hx:absolute hx:-mt-20" id="what-model-merging-is"></span>
    <a href="#what-model-merging-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For anyone not following this niche, model merging isn&rsquo;t magic. It&rsquo;s a fairly common technique: you take two compatible checkpoints, usually from the same architecture, and combine the weights. The simplest version is literally a linear interpolation:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">final_model = 0.6 * model_A + 0.4 * model_B</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There are more sophisticated variations: layer-wise merge, task vectors, TIES, DARE, SLERP, different weights per module. But the concept is this: you&rsquo;re not training from scratch. You&rsquo;re combining already trained parameters.</p>
<p>Can this work? Sometimes. Especially when the models share the same base and were tuned in complementary directions. It can preserve capabilities from one and recover base behavior from another. It can also make things worse. Merging is statistical alchemy: there is technique, but also a lot of empirical testing.</p>
<p>And, most importantly: <strong>merging costs nowhere near what it costs to train a 397B model</strong>. You need to download huge checkpoints, run scripts, test weights, maybe benchmark, maybe tune a few things. <strong>It is not zero work. But it is not &ldquo;we trained a frontier model.&rdquo;</strong></p>
<p>If Nex&rsquo;s evidence is correct, the published checkpoint was something like:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Rio 3.5 ≈ 0.57 to 0.60 * Nex-N2-Pro + 0.40 to 0.43 * Qwen3.5-397B-A17B</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That looks more like integration engineering than model training. It is not the same kind of technical merit as post-training or distilling a 397B and presenting it as your own advance.</p>
<h2>What distillation means here<span class="hx:absolute hx:-mt-20" id="what-distillation-means-here"></span>
    <a href="#what-distillation-means-here" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Distillation is a different thing. In LLMs, it usually means using a stronger teacher model to generate answers, reasoning traces, or preferences, and training a student model to imitate that behavior. You can distill style, reasoning ability, response format, a specific domain, tool use. The student can be smaller, cheaper, faster, or simply adapted to a goal.</p>
<p>Rio&rsquo;s corrected README says <strong>On-Policy Distillation from a stronger model</strong>. Roughly translated: they would have used a stronger model to generate training data or signals under a generation policy closer to the student itself, and then trained the final Rio 3.5.</p>
<p>That, if it exists, is real work. It requires a pipeline, data, compute, evaluation. The issue is that Nex did not analyze this alleged final distilled model. It analyzed the checkpoint that was public. And Rio now says that checkpoint was the &ldquo;merged base version&rdquo; uploaded by mistake.</p>
<p>So the factual state is:</p>
<ul>
<li>initially published checkpoint: accused of being a Nex + Qwen merge;</li>
<li>initial README: credited Qwen, not Nex;</li>
<li>corrected README: acknowledges Nex + Qwen merge and says the final distilled model was not that file;</li>
<li>correct final model: still open, until it is reuploaded and analyzed.</li>
</ul>
<p>Without the final checkpoint, we can&rsquo;t evaluate the distillation. We can evaluate the communication.</p>
<h2>The license: Apache allows it, but usually requires preserving notices<span class="hx:absolute hx:-mt-20" id="the-license-apache-allows-it-but-usually-requires-preserving-notices"></span>
    <a href="#the-license-apache-allows-it-but-usually-requires-preserving-notices" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is where a lot of online discussion gets dumb.</p>
<p>I am not a lawyer and this is not legal advice. Also, the exact application of open-source licenses to model weights still has gray areas. But in a practical reading of Apache-2.0, the operational rule is not &ldquo;use it and erase the traces.&rdquo;</p>
<p>Nex-N2-Pro declares <strong>Apache-2.0</strong> on Hugging Face: <a href="https://huggingface.co/nex-agi/Nex-N2-Pro/raw/main/README.md"target="_blank" rel="noopener">Nex-N2-Pro README</a>. Qwen3.5-397B-A17B also declares <strong>Apache-2.0</strong>: <a href="https://huggingface.co/Qwen/Qwen3.5-397B-A17B/raw/main/README.md"target="_blank" rel="noopener">Qwen3.5-397B-A17B README</a>.</p>
<p>Apache-2.0 is permissive. It allows reproduction, modification, derivative works, sublicensing, and distribution. Commercially too. So it is not &ldquo;theft&rdquo; simply because they used Nex and Qwen. If the license allows use, use is part of the game.</p>
<p>But permissive does not mean &ldquo;no obligations at all.&rdquo; The <a href="https://www.apache.org/licenses/LICENSE-2.0.txt"target="_blank" rel="noopener">Apache-2.0 license</a> requires, among other things:</p>
<ul>
<li>giving recipients a copy of the license;</li>
<li>marking modified files with prominent change notices;</li>
<li>preserving copyright, patent, trademark, and attribution notices from the source form;</li>
<li>including NOTICE when the original work has an applicable NOTICE.</li>
</ul>
<p>Rio 3.5 initially declared <strong>MIT License</strong> and credited Qwen/SwiReasoning, but not Nex. If the distributed checkpoint was in fact derived from Nex-N2-Pro, that is at least an attribution failure. It may be fixable. It seems to have been partially corrected in the README. But the error happened at launch, exactly at the moment of highest visibility.</p>
<p>And there is another nuance: <strong>you can&rsquo;t simply take two Apache-2.0 components, generate a derivative, and announce the resulting package as if it were only MIT, without preserving the Apache obligations from the upstreams</strong>.</p>
<p>Apache-2.0 is permissive and allows you to distribute derivatives under different terms for your modifications, but with conditions: you still need to provide the Apache license, preserve copyright/attribution notices, and carry NOTICE when one exists.</p>
<p>So &ldquo;MIT&rdquo; may appear as the license for Rio&rsquo;s added layer, but it cannot erase Apache-2.0 from Nex and Qwen or imply the whole derivative is free of those obligations. If the original card said only MIT and did not include the applicable Apache credits/notices, that can stop being just an etiquette slip and become a possible license-compliance problem.</p>
<p>There&rsquo;s an irony here: they could have avoided 90% of the controversy with one honest sentence from the start:</p>
<blockquote>
  <p>&ldquo;Rio 3.5 is a merge/fine-tune built on Nex-N2-Pro and Qwen3.5-397B-A17B, with IplanRIO adaptations for Portuguese and public-sector use.&rdquo;</p>

</blockquote>
<p>Done. Maybe people would still complain politically, but the technical criticism would be much weaker. The problem is looking like you did it alone.</p>
<h2>How much work does it look like?<span class="hx:absolute hx:-mt-20" id="how-much-work-does-it-look-like"></span>
    <a href="#how-much-work-does-it-look-like" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the speculative part, so I&rsquo;ll mark it as speculation.</p>
<p>If what was published was only the base merge, the technical work may have been much smaller than the public narrative suggested. Merging two giant models is not clicking a button in a browser, of course. You need storage, scripts, machines, validation, shard handling, uploading almost a hundred <code>safetensors</code>, tests, documentation. It is operational work.</p>
<p>But it is not the same kind of work as truly training, post-training, or distilling a 397B.</p>
<p>And the phrase &ldquo;open AI model trained in Rio with public funding over the last year,&rdquo; as Eduardo Cavaliere said in this <a href="https://x.com/CavaliereRio/status/2065984620626129026"target="_blank" rel="noopener">tweet</a>, creates a very different expectation from &ldquo;we merged two Apache models and maybe distilled afterward.&rdquo;</p>
<p>Rafael Coelho replied in another <a href="https://x.com/RafaelC38655518/status/2066044310206771250"target="_blank" rel="noopener">tweet</a> that they had not spent public money and had swapped old training code for GPU credits. There may be an administrative explanation there, but from the outside the communication is confusing.</p>
<p>I am not claiming administrative wrongdoing. I am saying the public narrative became inconsistent.</p>
<p>And even the <strong>R$ 500,000</strong> figure, cited by Mobile Time about the previous generation, needs scale. In serious LLM research, that is not a lot of money. Add salaries for a few researchers, infrastructure, storage, cloud GPU hours, failed attempts, evaluation, data engineering, and that amount disappears quickly. It&rsquo;s a drop in the ocean compared with the cost of training or post-training a genuinely large model.</p>
<p>So I would not use &ldquo;R$ 500,000&rdquo; as automatic proof of waste. That&rsquo;s not the point. The point is different: that amount also does not, by itself, support a narrative that a heavy, original 397B training run happened. For that kind of scale, serious research would spend much, much more.</p>
<p>Was it publicly funded? Was it not? Did it cost R$ 500,000 in the previous generation? Was it GPU credits? Was it a year of training? Was it a merge? Was it distillation? Was it a wrong upload?</p>
<p>Maybe all those sentences have different contexts. But when technical communication is bad, the public stitches everything together and it becomes a mess.</p>
<h2>What my benchmark says about Nex and Qwen<span class="hx:absolute hx:-mt-20" id="what-my-benchmark-says-about-nex-and-qwen"></span>
    <a href="#what-my-benchmark-says-about-nex-and-qwen" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now comes the part where I can speak from my own data. In my <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">llm-coding-benchmark</a>, I tested both <strong>Nex-N2-Pro</strong> and the <strong>Qwen 3.5 397B A17B base</strong>.</p>
<p>My benchmark measures one specific programming/Rails task. It is useful as a signal, not as a general capability evaluation.</p>
<p>I did not test Rio 3.5 directly for a simple reason: it is too large for my local machine. My Strix Halo has 128 GB of unified RAM, great for many things, but not enough to run a 397B model like this comfortably. To test it properly, I would need to rent a cloud machine, deal with setup, download hundreds of gigabytes, organize shards, start an inference server, pay by the hour, and still risk the correct checkpoint not even being available at that moment.</p>
<p>I was not up for all that work for a quick analysis post. So I used the best available approximation: test the originals that the controversy itself puts in the recipe, Nex-N2-Pro and Qwen3.5-397B-A17B. If the published Rio was basically a merge of those two, and if there is no public evidence of much effective work on top of that checkpoint, comparing the ingredients already says a lot. It does not replace a direct Rio test, but it puts the performance claim in perspective.</p>
<p>There&rsquo;s another detail: in <a href="https://huggingface.co/prefeitura-rio/Rio-3.5-Open-397B/raw/cd503cdc7aaac2506bf68f6d278503ddb07a83ef/README.md"target="_blank" rel="noopener">Rio&rsquo;s own old model card</a>, the table said &ldquo;Gains Over Base Model&rdquo;, but Rio <strong>did not beat Qwen 3.5 base on everything</strong>.</p>
<p>It lost on MMLU-Redux (94.6 vs 94.9), MMMU-Pro (78.4 vs 79.0), and VideoMMMU (81.6 vs 84.7), tied on MCP-Atlas (74.2 vs 74.2), and in some cases won by small margins, like MMLU-Pro (88.0 vs 87.8) and MathVision (89.1 vs 88.6). So even by the self-reported numbers, without independent auditing, the story was more &ldquo;improves on several benchmarks&rdquo; than &ldquo;better than Qwen at everything.&rdquo;</p>
<p>And yes, where Rio said it beat Qwen, that also fits Nex&rsquo;s hypothesis: <strong>Nex-N2-Pro was already better than the Qwen base precisely because of Nex&rsquo;s work</strong>. I saw this in my own benchmark: Qwen3.5-397B-A17B base scored 42/C, while Nex-N2-Pro scored 83/A. So a Rio that mixes Nex with Qwen can very well look better than Qwen. For the published checkpoint, the simpler explanation is not &ldquo;Rio invented a miracle technique&rdquo;; it&rsquo;s &ldquo;it inherited much of the gain Nex had already produced on top of Qwen.&rdquo;</p>
<p>Relevant commits:</p>
<ul>
<li><a href="https://github.com/akitaonrails/llm-coding-benchmark/commit/11a9c6850485215bb6ccc2ab8e3d1c60e175e62b"target="_blank" rel="noopener"><code>11a9c68</code></a>: adds Nex-N2-Pro, 83/100, Tier A.</li>
<li><a href="https://github.com/akitaonrails/llm-coding-benchmark/commit/e2af88c77c4c5abd95438d5a6132d2bfdf7d943b"target="_blank" rel="noopener"><code>e2af88c</code></a>: adds Qwen 3.5 397B A17B base, 42/100, Tier C.</li>
</ul>
<p>In the final benchmark table, Nex landed here: <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/e2af88c77c4c5abd95438d5a6132d2bfdf7d943b/docs/success_report.md#L77-L89"target="_blank" rel="noopener">rank #10, 83/100, Tier A</a>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Nex-N2-Pro | 83 | A | RubyLLM OK | OpenRouter | 25m | free</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The Qwen base landed here: <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/e2af88c77c4c5abd95438d5a6132d2bfdf7d943b/docs/success_report.md#L102-L108"target="_blank" rel="noopener">rank #28, 42/100, Tier C</a>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Qwen 3.5 397B A17B (base) | 42 | C | RubyLLM not OK | OpenRouter | 15m | ~$0.58</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That&rsquo;s an interesting control. Same backbone, completely different result.</p>
<p>The Qwen base hallucinated the RubyLLM API (<code>chat.system</code>, <code>chat.user</code>, <code>response.text</code>) and even created the app inside a nested <code>chat-app/</code> directory, violating the expected benchmark shape.</p>
<p>Nex, on the other hand, used the real API: <code>RubyLLM.chat</code>, <code>chat.ask</code>, <code>response.content</code>, booted locally, passed Docker, compose, and real chat through OpenRouter. The report compares it directly: <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/e2af88c77c4c5abd95438d5a6132d2bfdf7d943b/docs/success_report.md#L570-L581"target="_blank" rel="noopener">Qwen base 42/C vs Nex tuned 83/A, a 41-point jump</a>.</p>
<p>That puts Rio 3.5 in perspective. If it really was 60% Nex + 40% Qwen base, it makes sense that it would inherit a lot of Nex&rsquo;s agent capability. But it also makes sense to suspect that mixing in 40% of a model that did much worse in my programming test could degrade pure Nex in some scenarios.</p>
<p>So I won&rsquo;t claim &ldquo;Rio is worse&rdquo; as my own measurement. What I can say is: <strong>the Nex component is good; the Qwen base component was bad in my test; a Rio that was only Nex diluted with Qwen base should not be sold as an obvious advance over pure Nex without a reproducible benchmark against Nex itself</strong>. From what has been published so far, it does not look like the work on top of the merge improved the ranking in a demonstrable way. If it did, publish the correct model and reproducible tests.</p>
<p>And even Nex, which did very well, was not at the top of my open or open-ish ranking. It scored 83. The best so far were Kimi K2.6 and GLM 5.2 at 87, and Kimi K2.7 Code at 86. Nex is Tier A, free, impressive. But it is not magic. It is a good agent-focused fine-tune on top of a family that, raw, badly trips on library APIs.</p>
<p>So as a user, my practical conclusion is simple: <strong>if I had to choose today, I would use Nex-N2-Pro directly</strong>. Not because Rio is automatically useless forever, but because the published checkpoint did not show a clear, auditable gain over the most valuable ingredient in the recipe. If the gain came from Nex, why not use Nex? Rio becomes technically interesting again only if the correct final distilled model appears, with reproducible evaluation showing a real advantage over pure Nex-N2-Pro.</p>
<h2>So was it plagiarism?<span class="hx:absolute hx:-mt-20" id="so-was-it-plagiarism"></span>
    <a href="#so-was-it-plagiarism" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>My honest answer: <strong>I would not call it plagiarism as a legal conclusion</strong>. I would call it a poorly attributed repackaging of the initially published checkpoint, with strong evidence of a direct merge and a correction that only appeared after exposure.</p>
<p>Open source is not &ldquo;you can&rsquo;t use it.&rdquo; Open source is &ldquo;you can use it, but respect the license and give credit.&rdquo; If Nex and Qwen are Apache-2.0, the city could build on top of them. It could merge. It could distill. It could publish a derivative. It could even license its own layer under MIT, as long as it does not erase the Apache obligations from the components and preserves the required notices.</p>
<p>The mistake was letting the public narrative look like an original creation, with incomplete credit. And then, when Nex showed up with tensor-by-tensor math, the README changed.</p>
<p>Maybe there is a real final distilled model. If there is, publish it. Preferably with:</p>
<ul>
<li>a clear card stating the base, merge, distillation, and training data;</li>
<li>a license compatible with Qwen and Nex;</li>
<li>explicit credits;</li>
<li>a reproducible evaluation script;</li>
<li>a benchmark against pure Nex-N2-Pro and Qwen base;</li>
<li>an explanation of the &ldquo;incorrect upload.&rdquo;</li>
</ul>
<p>That would close much of the technical discussion. Maybe not the political one, but the technical one, yes.</p>
<h2>What to learn from this<span class="hx:absolute hx:-mt-20" id="what-to-learn-from-this"></span>
    <a href="#what-to-learn-from-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This story is a good reminder for everyone surfing open models now. The derivation chain matters. Not because of academic bureaucracy, but because it is part of trust.</p>
<p>If you fine-tune on top of Qwen, say Qwen. If you merge with Nex, say Nex. If you distill from a closed teacher, say you distilled, even if you can&rsquo;t name the teacher. If you uploaded the wrong checkpoint, explain exactly which one was wrong, which one is right, and how someone can verify it.</p>
<p>The worst path is trying to look bigger than you are. Because open LLMs are an environment where weights can be downloaded, compared, and audited. You can hide the narrative for a while, but you cannot hide linear algebra.</p>
<p>In the end, Nex may have received the best involuntary validation of its own model: if a city government used Nex-N2-Pro as 60% of the recipe for a model announced as &ldquo;state of the art,&rdquo; then Nex is good. But involuntary validation does not pay the credit bill.</p>
<p>And credit, in open source, is not fussiness. It is the basic currency of the game.</p>
]]></content:encoded><category>llms</category><category>open-source</category><category>law-and-regulation</category></item><item><title>Playing with TUIs and LLMs - Ratatui+Bubbletea</title><link>https://akitaonrails.github.io/en/2026/06/08/playing-with-tuis-llms-ratatui-bubbletea/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/06/08/playing-with-tuis-llms-ratatui-bubbletea/</guid><pubDate>Mon, 08 Jun 2026 16:00:00 -0300</pubDate><description>&lt;p&gt;Before getting to the new toy, a quick reminder: &lt;a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener"&gt;ai-jail&lt;/a&gt; and &lt;a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener"&gt;ai-memory&lt;/a&gt; are still getting plenty of attention. Issues, pull requests, small fixes, packaging improvements, environment bugs, documentation tweaks. The stuff nobody sees in a launch post, but that turns an experiment into something you can use every day.&lt;/p&gt;
&lt;p&gt;I like this phase. The project stops being &amp;ldquo;what I imagined in my setup&amp;rdquo; and becomes &amp;ldquo;what breaks on somebody else&amp;rsquo;s machine.&amp;rdquo; Then Windows shows up. macOS. Arch. AUR. Weird paths. Tokens saved somewhere else. Different shell. Different terminal. Annoying? Yes. Necessary? Also yes.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Before getting to the new toy, a quick reminder: <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a> and <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a> are still getting plenty of attention. Issues, pull requests, small fixes, packaging improvements, environment bugs, documentation tweaks. The stuff nobody sees in a launch post, but that turns an experiment into something you can use every day.</p>
<p>I like this phase. The project stops being &ldquo;what I imagined in my setup&rdquo; and becomes &ldquo;what breaks on somebody else&rsquo;s machine.&rdquo; Then Windows shows up. macOS. Arch. AUR. Weird paths. Tokens saved somewhere else. Different shell. Different terminal. Annoying? Yes. Necessary? Also yes.</p>
<p>But today&rsquo;s main dish is not ai-jail or ai-memory. It&rsquo;s TUI. More specifically, my recent habit of writing small terminal tools in Rust with <a href="https://ratatui.rs/"target="_blank" rel="noopener">Ratatui</a>, while wanting them to look like <a href="https://github.com/charmbracelet/bubbletea"target="_blank" rel="noopener">Bubble Tea</a>.</p>
<h2>The app I won&rsquo;t open<span class="hx:absolute hx:-mt-20" id="the-app-i-wont-open"></span>
    <a href="#the-app-i-wont-open" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Over the last few weeks I also worked on a private project I do not plan to open source. It&rsquo;s a TUI to track my US bank account, investments, assets, positions, covered calls, open calls, all that boring grown-up stuff. I won&rsquo;t publish the code because this tool was born glued to my financial workflow, my spreadsheets, my statements, and my internal hacks. Opening it would turn a tool for myself into free support for other people&rsquo;s bank bugs. No thanks.</p>
<p>But I can show the general look. I censored what needed censoring:</p>
<p><strong>Obvious note, but I&rsquo;ll make it explicit: every value, ticker, position, and date shown in the screenshot is bogus demonstration data. It is not real account data, not my real portfolio, and not investment advice.</strong></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/private-portfolio-censored.png" alt="Private portfolio TUI in a terminal, with dashboard tabs and a holdings table. The bank name was censored."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/private-allocation-censored.png" alt="Private TUI showing an asset allocation view, with sensitive names censored."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/private-open-calls-censored.png" alt="Private TUI showing an open calls tab with bogus demonstration data and sensitive names censored."  loading="lazy" /></p>
<p>Every time I build a small TUI, the same question comes back: what stack should I use?</p>
<p>If I were writing everything by hand, I would probably pick Python or Go. They are more comfortable for this kind of small utility. Python because it is direct, full of libraries, great for scripts that talk to APIs and parse JSON. Go because it produces simple binaries, cross-platform support is sane, and the CLI ergonomics are good.</p>
<p>But today I rarely write all that code by hand. I orchestrate Claude, Codex, OpenCode, ask for reviews, ask for refactors, ask for tests. In that setup, Rust&rsquo;s lack of ergonomics hurts less, because the LLM is the one fighting the borrow checker, trait bounds, and annoying lifetimes. I stay closer to reviewer and end user. And then Rust starts looking very attractive.</p>
<p>Good tooling. <code>cargo</code> is great. Tests are easy to run. Cross compile is manageable. The final binary is clean. Dumb memory bugs mostly disappear. I am not saying Rust is magically better than Go or Python for every TUI. It isn&rsquo;t. But with an LLM writing most of it, the cost that would usually make me avoid Rust drops a lot. And current models are surprisingly competent with Rust, as long as you make them run tests, fix warnings, and you don&rsquo;t accept the first version as if Moses brought it down from the mountain.</p>
<h2>Ratatui is good, but I wanted the Charm look<span class="hx:absolute hx:-mt-20" id="ratatui-is-good-but-i-wanted-the-charm-look"></span>
    <a href="#ratatui-is-good-but-i-wanted-the-charm-look" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://ratatui.rs/"target="_blank" rel="noopener">Ratatui</a> is a Rust library for building full terminal interfaces: dashboards, interactive apps, tables, lists, gauges, layouts, the whole thing we used to call &ldquo;modern ncurses.&rdquo; It grew out of <code>tui-rs</code>, and today it is probably the obvious path if you want to build a serious TUI in Rust.</p>
<p>Ratatui works well. My problem is taste: by default, I don&rsquo;t find it pretty. Not ugly in the &ldquo;this looks like a DOS program from 1993&rdquo; sense. You can build good-looking stuff with it. But many Ratatui TUIs fall into that square, gray, functional look, like a datacenter admin panel.</p>
<p>I like the <a href="https://charm.sh/"target="_blank" rel="noopener">Charmbracelet</a> vibe more. <code>gum</code>, for example, is a collection of commands that make shell scripts interactive without turning them into a festival of <code>read -p</code> and <code>case</code>. Prompt, select, filter, spinner, table, pager, styling. You can make a bash script feel like a decent app in minutes.</p>
<p>And then there is <a href="https://github.com/charmbracelet/bubbletea"target="_blank" rel="noopener">Bubble Tea</a>, in Go, inspired by Elm architecture. You have a model, receive messages, update state, render a view. Simple idea, very good fit for terminal apps: state comes in, event comes in, view goes out. Charm also has visual taste I like: good colors, decent spacing, light components, nothing that looks like a WinForms form thrown into a terminal.</p>
<p>So I wanted this: stay in Rust with Ratatui, but steal the feeling of Bubble Tea. Not the whole runtime. Not a perfect clone. Just the visual direction and a few components.</p>
<p>That is how <a href="https://github.com/akitaonrails/ratatui-bubbletea"target="_blank" rel="noopener">ratatui-bubbletea</a> was born.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/ratatui-bubbletea-example.png" alt="ratatui-bubbletea demo running in a terminal, with SelectList, Spinner, Theme, ThemedTable, TextInput, Progress, and Viewport in a Charm-like style."  loading="lazy" /></p>
<p>The project does not replace Ratatui. It sits on top. The idea is to offer a theme and component layer inspired by Bubble Tea/Bubbles, while still rendering through Ratatui.</p>
<p>Right now it is split into crates:</p>
<ul>
<li><code>ratatui-bubbletea-theme</code>, with palette, helpers, and shared styles.</li>
<li><code>ratatui-bubbletea-components</code>, with ready-made components like select list, spinner, progress, table, text input, viewport, and help.</li>
<li><code>ratatui-tea</code>, optional, for people who want ergonomics closer to <code>Model</code>, <code>Msg</code>, and <code>Cmd</code>, without pretending Rust became Go.</li>
</ul>
<p>The README has the full examples and documentation for what exists today. For now, I treat it as a small toolkit. It serves my apps, and if it serves somebody else, fine. If it doesn&rsquo;t, no drama either. The goal was to stop reimplementing the same theme and the same widgets every time I started a new TUI.</p>
<h2>ai-usagebar as the public example<span class="hx:absolute hx:-mt-20" id="ai-usagebar-as-the-public-example"></span>
    <a href="#ai-usagebar-as-the-public-example" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Since I won&rsquo;t open the financial app, I needed a public example using this aesthetic. So I updated my <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>.</p>
<p>If you don&rsquo;t remember it, I explained the project in <a href="/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/">&ldquo;I Built a Waybar Widget for Omarchy to Monitor LLM Plan Usage: ai-usagebar&rdquo;</a>. It started as a Waybar widget to show LLM plan usage: Claude, OpenAI Codex/ChatGPT, Z.AI, OpenRouter. One glance at the bar and I know whether I am close to the limit and which vendor to use next.</p>
<p>Later it also became a standalone TUI. And thanks to contributions, it now supports Windows too. That is funny because its origin is completely Linux/Omarchy/Waybar. But that is open source: somebody uses it in another environment, finds friction, sends a PR, and now the project is a little less provincial.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/ai-usagebar.png" alt="ai-usagebar in TUI mode showing an OpenAI usage dashboard, vendor tabs, limit gauges, and footer shortcuts."  loading="lazy" /></p>
<p>In ai-usagebar, the visual change will not alter anybody&rsquo;s life. It is a simple screen. Tabs, gauges, text, shortcuts. But it is a good example because it is small, real, tested, packaged, and does not depend on my private app. You can look at the code and see how I applied the theme layer.</p>
<h2>The scratch-my-own-itch apps<span class="hx:absolute hx:-mt-20" id="the-scratch-my-own-itch-apps"></span>
    <a href="#the-scratch-my-own-itch-apps" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>All these projects follow the same logic: I have an itch, I make a small tool, I use it, adjust it, package it. No startup roadmap. No manifesto. Just a tool that fixes something annoying in my own setup.</p>
<p>One recent example is <a href="https://github.com/akitaonrails/clock-tui"target="_blank" rel="noopener">clock-tui</a>. It did not start with me. It was an old Rust project, <code>tclock</code>, that looked abandoned. I wanted a big clock on my second vertical monitor. That monitor sits on the side, and I like having a huge desk clock taking up part of the screen. I used the original clock-tui for a while.</p>
<p>But an entire vertical screen just to show the time is wasteful. I already had <a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a>, which lists open issues and PRs across all my projects. It is my &ldquo;is anybody waiting for an answer?&rdquo; in CLI form. I also wanted to see my agenda.</p>
<p>So I made another small app: <a href="https://github.com/akitaonrails/google-calendar-tui"target="_blank" rel="noopener">google-calendar-tui</a>. It uses the Gmail accounts already registered in GNOME Online Accounts and summarizes my upcoming appointments in the terminal. Read-only. No new OAuth ritual. No extra secret config scattered somewhere weird.</p>
<p>With those two pieces, I modernized clock-tui and added auto-refreshing widget layout support. Now the clock takes the screen the way I wanted, but around it I also get GitHub pending work and Google Calendar appointments.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/tclock.png" alt="tclock on a vertical monitor, with a large clock, GitHub pending widget on the left, and Google Calendar agenda on the right."  loading="lazy" /></p>
<p>This is exactly the kind of thing I would never build if it cost me an entire weekend. But with an LLM, it becomes a sequence of small tasks: read the old project, modernize dependencies, run tests, add a widget module, call ghpending, call google-calendar-tui, organize layout, fix bugs, package. It still takes work. But it is supervision and refinement work, not fighting boilerplate.</p>
<h2>Tweaking Geary without a fork<span class="hx:absolute hx:-mt-20" id="tweaking-geary-without-a-fork"></span>
    <a href="#tweaking-geary-without-a-fork" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Another itch came from GNOME.</p>
<p>Since I wanted to centralize my accounts in GNOME Online Accounts, I started using <a href="https://wiki.gnome.org/Apps/Geary"target="_blank" rel="noopener">Geary</a> and GNOME Calendar on the second monitor too. I like the idea: accounts configured once, desktop apps reusing the same infrastructure, no tiny program inventing its own login flow.</p>
<p>The problem is that Geary has a fixed three-column layout. On a normal screen, fine. On a vertical monitor, it gets cramped. The folder column, message list, and email body fight for space. I did not want to maintain a Geary fork just to hide a sidebar. Forking a large GTK app is debt. You blink and spend the rest of your life resolving merge conflicts.</p>
<p>So I made a GTK module: <a href="https://github.com/akitaonrails/geary-hide-sidebar-module"target="_blank" rel="noopener">geary-hide-sidebar-module</a>. It injects behavior into Geary at runtime and lets me collapse/expand the sidebar, with a shortcut and auto-collapse for narrow windows. No rebuilding Geary. No fork to maintain. Just a small module with one very specific job.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/geary-sidebar-hidden.png" alt="Geary with the sidebar collapsed, showing the email list and message body in a more comfortable layout for a vertical screen."  loading="lazy" /></p>
<p>This is a good lesson: sometimes you do not need to fork the whole application. You can adjust it from the outside. GTK_MODULES exists. Wrappers exist. Config exists. CSS exists. Scripts exist. Not every customization has to become eternal maintenance of somebody else&rsquo;s code.</p>
<h2>Small code got cheap<span class="hx:absolute hx:-mt-20" id="small-code-got-cheap"></span>
    <a href="#small-code-got-cheap" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>That is why I keep insisting on this idea of small apps. With current LLMs, it became very easy to implement a specific idea to make your environment fit your needs. No waiting for someone else to have the exact same pain. No searching GitHub for three hours for a tool that does 80% of what you want and 40% of what you don&rsquo;t want.</p>
<p>You describe the itch, create a repo, ask for a prototype, test it, ask for refactoring, ask for tests, ask for packaging. If it sucks, throw it away. If it works, install it and use it.</p>
<p>I do not let this turn into random junk dumped in <code>~/bin</code> with no owner. My apps have tests. They have automated builds. Many have GitHub releases, AUR packages, normal installation with <code>yay</code> on Arch. They use XDG paths, so config goes to <code>~/.config</code>, cache goes to <code>~/.cache</code>, data goes to <code>~/.local/share</code>. Organized. Upgradable. Removable. Something another person can clone and contribute to.</p>
<p>Here are all the links in one place:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ratatui-bubbletea"target="_blank" rel="noopener">ratatui-bubbletea</a></li>
<li><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a></li>
<li><a href="https://github.com/akitaonrails/clock-tui"target="_blank" rel="noopener">clock-tui</a></li>
<li><a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a></li>
<li><a href="https://github.com/akitaonrails/google-calendar-tui"target="_blank" rel="noopener">google-calendar-tui</a></li>
<li><a href="https://github.com/akitaonrails/geary-hide-sidebar-module"target="_blank" rel="noopener">geary-hide-sidebar-module</a></li>
<li><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a></li>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a></li>
</ul>
<p>If you use any of them and it breaks in your setup, open an issue. If you know how to fix it, send a PR. I actually use these tools, so useful bug reports tend to turn into fixes fast.</p>
<p>My practical rule is this: customize your environment without turning everything into duct tape. Build small tools. Test them. Package them. Document them. Let the LLM carry the boring weight and use your brain to decide what is worth keeping.</p>
<p>That is the fun part of programming that had gone missing for a bit. Now it is back.</p>
]]></content:encoded><category>ai-usagebar</category><category>developer-tools</category><category>rust</category><category>open-source</category></item><item><title>AI Controversy in Open Source Project Contributions - My Take</title><link>https://akitaonrails.github.io/en/2026/06/05/ai-controversy-open-source-project-contributions-my-take/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/06/05/ai-controversy-open-source-project-contributions-my-take/</guid><pubDate>Fri, 05 Jun 2026 11:00:00 -0300</pubDate><description>&lt;p&gt;Over the last few days, the discussion around &lt;strong&gt;AI slop&lt;/strong&gt; in open source projects came back. Maintainers complaining that AI-generated PRs are garbage. Projects banning AI-assisted contributions. Bug bounty programs getting flooded with fake reports. Users angry because a release that used AI broke something. And, of course, the internet doing what the internet does best: turning one specific case into a holy war.&lt;/p&gt;
&lt;p&gt;My short take: &lt;strong&gt;AI in open source contributions is here to stay&lt;/strong&gt;. It will increase, not decrease. Pandora&amp;rsquo;s box is already open. There is no realistic plan where everyone goes back to programming 100% manually and pretends Claude Code, Codex, OpenCode, Cursor, Gemini CLI, and the rest never existed.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Over the last few days, the discussion around <strong>AI slop</strong> in open source projects came back. Maintainers complaining that AI-generated PRs are garbage. Projects banning AI-assisted contributions. Bug bounty programs getting flooded with fake reports. Users angry because a release that used AI broke something. And, of course, the internet doing what the internet does best: turning one specific case into a holy war.</p>
<p>My short take: <strong>AI in open source contributions is here to stay</strong>. It will increase, not decrease. Pandora&rsquo;s box is already open. There is no realistic plan where everyone goes back to programming 100% manually and pretends Claude Code, Codex, OpenCode, Cursor, Gemini CLI, and the rest never existed.</p>
<p>That does not mean every project is obligated to accept AI-assisted contributions. Far from it. The maintainer has the absolute right to run the project however they want. They can accept AI, ban AI, freeze the project, delete the repository and go grow tomatoes. Open source is not mandatory democracy. Whoever maintains decides.</p>
<p>But I also think banning AI is mostly delaying a fight you cannot win. The volume will keep going up. Average quality will wobble. There will be trash, there will be good work, there will be almost-right PRs, there will be hallucinated bug reports. The practical question is not &ldquo;how do we stop AI?&rdquo; The practical question is: <strong>how do we adapt the process to survive this?</strong></p>
<h2>The recent cases<span class="hx:absolute hx:-mt-20" id="the-recent-cases"></span>
    <a href="#the-recent-cases" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The loudest case right now was <a href="https://linuxiac.com/rsync-3-4-3-regressions-trigger-debate-over-ai-assisted-code/"target="_blank" rel="noopener">rsync 3.4.3</a>. The version shipped on May 20 as a security update, fixing six CVEs. Soon after, users reported regressions, especially in backup flows using daemon mode and incremental transfer options. Rsync is not a toy. It is a backup, deploy, mirror, sysadmin tool. Breaking compatibility there hurts.</p>
<p>Andrew Tridgell, creator of Samba and co-creator of rsync, answered in the post <a href="https://medium.com/@tridge60/rsync-and-outrage-d9849599e5a0"target="_blank" rel="noopener">rsync and outrage</a>. He confirmed that he used Claude, with cross-checks from Codex and Gemini, to help rewrite part of the test suite in Python. But he also said the obvious thing a lot of people do not want to hear: he did not type &ldquo;convert all of this&rdquo; and go to sleep. He designed the suite, reviewed the work, burned a lot of CI time, and acknowledged that regressions happened in valid but uncommon cases that were covered neither by the existing tests nor by his manual testing.</p>
<p>That is the interesting point: the regression became a discussion about AI, but regression was not born with AI. Regression was born with software.</p>
<p>On the other side we have Zig. The <a href="https://ziglang.org/code-of-conduct/"target="_blank" rel="noopener">Zig Code of Conduct</a> today has an explicit policy: <strong>Strict No LLM / No AI Policy</strong>. No LLM-generated content, not code, not prose, not grammar edits, not translation, not brainstorming. Andrew Kelley explained in an interview, summarized by <a href="https://www.devclass.com/devops/2026/06/01/zig-creator-seeks-uncompromising-perfection-before-blessing-10/5248219"target="_blank" rel="noopener">DevClass</a>, that the team considers AI contributions invariably bad, review-time sinks, unteachable, non-deterministic. The line that sums up his position is a good one: the bar he wants is not &ldquo;works surprisingly well,&rdquo; it is &ldquo;uncompromising perfection.&rdquo;</p>
<p>I disagree with the generalization, but I respect the decision. It is his project. If he wants to keep that space free of LLMs, that is his right. Period.</p>
<p>In the same neighborhood came the Bun discussion. The <a href="https://bun.sh/blog/bun-joins-anthropic"target="_blank" rel="noopener">official post about Bun joining Anthropic</a> says Bun was acquired because Claude Code and other Anthropic coding products depend on it. &ldquo;If Bun breaks, Claude Code breaks,&rdquo; in the post&rsquo;s own words. Meanwhile, the <a href="https://www.cosmicjs.com/blog/bun-rust-rewrite-javascript-runtime"target="_blank" rel="noopener">Cosmic piece about the Rust rewrite</a> points to reasons like contributor accessibility, maintainability at scale, and long-term stability. I saw people linking this to Zig&rsquo;s anti-AI policy, but the source I could verify does not state that causality. What we can safely say is: Bun, a project born in Zig, is moving important parts to Rust, and one stated reason is Rust&rsquo;s larger contributor base.</p>
<p>Then there is curl. According to <a href="https://hackaday.com/2026/01/26/the-curl-project-drops-bug-bounties-due-to-ai-slop/"target="_blank" rel="noopener">Hackaday</a>, Daniel Stenberg suspended curl&rsquo;s bug bounty program starting February 1, 2026 because the project was flooded with LLM-generated vulnerability reports. Long reports, intimidating, with the shape of a serious exploit, but when an experienced maintainer reads them, they are not vulnerabilities. The PR removing the bounty is on GitHub as <a href="https://github.com/curl/curl/pull/20312"target="_blank" rel="noopener">curl/curl#20312</a>.</p>
<p>That case is different from a code PR. It is worse. A bad patch you test, compile, read. A fake security report forces someone experienced to spend time proving that the bug does not exist. That is the kind of thankless work that burns maintainers out.</p>
<p>So yes: the problem is real. AI slop exists. It is filling issue trackers, PRs, bug bounties, comments, everything.</p>
<p>Now the part nobody likes: it will not stop.</p>
<h2>There is no &ldquo;back to normal&rdquo;<span class="hx:absolute hx:-mt-20" id="there-is-no-back-to-normal"></span>
    <a href="#there-is-no-back-to-normal" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I already talked about this in <a href="/en/2026/04/11/vs-code-is-the-new-punch-card/">VS Code Is the New Punch Card</a>. The interface changed. First you had to type binary instructions. Then you had to organize punch cards. Then you had to convince the compiler. Then you had to operate editor, terminal, framework, CI, container, cloud, and YAML. Now you have to orchestrate agents.</p>
<p>This does not eliminate engineering. It only changes where the manual work ends.</p>
<p>Some people are treating AI like a passing fad, like the &ldquo;metaverse&rdquo; or NFTs. It is not. AI for programming is already past the conference-demo stage. It is inside real workflows. Rsync used it. Bun has Claude Code bots opening PRs. My projects use it. Your contributors will use it, even if you forbid it. If you think you can detect with 100% certainty whether a patch was written with or without AI, good luck with that one.</p>
<p>The maintainer can still set a rule. They can say &ldquo;if I find out you used AI, I block you.&rdquo; That may make sense in small communities with their own culture, like Zig. But in open source at large, especially big projects with users all over the world, this turns into compliance theater. The person uses AI, rewrites the text, does not disclose it, and that&rsquo;s that. What are you going to do? AI detector for code? For crying out loud.</p>
<h2>The mistake is thinking you have to review everything alone<span class="hx:absolute hx:-mt-20" id="the-mistake-is-thinking-you-have-to-review-everything-alone"></span>
    <a href="#the-mistake-is-thinking-you-have-to-review-everything-alone" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The fairest maintainer complaint is simple: there already are not enough people to review human contributions. AI increases volume. More PRs, more issues, more bug reports. The maintainer was already tired, now they are underwater.</p>
<p>I get it. I just do not think the solution is to process the new volume with the old process.</p>
<p>You fight AI with AI.</p>
<p>The first triage has to be done with an LLM. Not to approve automatically. To filter. To summarize. To compare the diff against the stated goal. To point out bad smells. To say &ldquo;this touches schema, it needs a migration.&rdquo; To say &ldquo;this changes public behavior, it needs compatibility tests.&rdquo; To say &ldquo;this PR description does not match the code.&rdquo; That layer alone removes 80% of the grunt work.</p>
<p>The mistake is letting the agent decide alone. The right move is making the agent do the boring investigation, then you decide.</p>
<p>That is how I do it.</p>
<h2>My real PR flow<span class="hx:absolute hx:-mt-20" id="my-real-pr-flow"></span>
    <a href="#my-real-pr-flow" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Anyone who followed my <a href="/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/">AI marathon</a> knows I did not get here after watching two YouTube videos. I spent weeks using agents every day, on real projects, breaking real things, fixing real things. What I am describing here is the workflow that survived that, not LinkedIn theory.</p>
<p>Shameless propaganda: I am happy that my three main AI-related projects are getting contributions almost every day:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a>, which I already covered in <a href="/en/2026/03/01/ai-jail-sandbox-for-ai-agents-from-shell-script-to-real-tool/">ai-jail: Sandbox for AI Agents</a>.</li>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>, which I explained in <a href="/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/">I Built a Memory System for Coding Agents: ai-memory</a>.</li>
<li><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>, from <a href="/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/">I Built a Waybar Widget for Omarchy to Monitor LLM Plan Usage: ai-usagebar</a>.</li>
</ul>
<p>ai-memory in particular became a live experiment. As I write this, GitHub shows <strong>55 closed PRs</strong> in the project; through the <code>gh</code> API, 46 were merged and 9 were closed without merge. Thanks to everyone who contributed. Seriously. Djalma, mrpaiva, pedrofjr, CaTeIM, azevedo-luis, brunoomariano, rikelmyso7, abnersajr, and several others. That is a lot of work from a lot of people.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/05/ia-open-source-contribuicoes/screenshot-ai-projects.png" alt="GitHub closed Pull Requests screen for ai-memory, showing 55 closed PRs and several recent PRs from contributors."  loading="lazy" /></p>
<p>It is also obvious, looking at the style, that most of those PRs were made with AI assistance. And that is not a problem. It would be hypocritical to complain: <strong>the entirety of ai-memory was written by AI</strong>. I did not open a code editor once to write that thing by hand.</p>
<p>But almost no PR arrives immediately mergeable. That is the point a lot of people still do not understand. &ldquo;Made with AI&rdquo; does not mean &ldquo;blind merge.&rdquo; It means &ldquo;the audit begins.&rdquo;</p>
<p>My prompt for reviewing a PR is more or less this:</p>
<blockquote>
  <p>check the latest open PR as usual: do not trust the author, audit the whole code thoroughly, make sure it achieves its goal.</p>
<p>Check whether we need to adjust or fix anything before merging: do not accept regressions, do not accept degraded code quality, check whether test coverage is correct.</p>
<p>If it touches build or OS support, check GitHub Actions, CI, clean build, correct wiring, and documentation.</p>
<p>Summarize what the PR does, what you found, and ask me for approval before proceeding.</p>

</blockquote>
<p>Notice two things. First: &ldquo;do not trust the author.&rdquo; That is not rudeness. It is engineering. The PR description is a hypothesis. The diff is the evidence. Second: &ldquo;ask me for approval.&rdquo; The agent investigates, I decide.</p>
<p>When I receive several PRs on the same day, I do this for all of them. After they are all in, I send another prompt:</p>
<blockquote>
  <p>check today&rsquo;s commits.</p>
<p>We touched a lot of code, so I need a complete audit of the touched code to make sure we did not add regressions, unnecessary duplication, dead code, or magic values that should become documented constants.</p>
<p>Follow clean code principles, confirm test coverage, and refactor whatever is needed.</p>

</blockquote>
<p>If the project is already in use, I add the part many people forget:</p>
<blockquote>
  <p>this project is already being used. Do not break compatibility.</p>
<p>If we touched database schema or user-file structures, there must be a clean migration on upgrade.</p>
<p>Upgrade must not corrupt data.</p>

</blockquote>
<p>This guarantees nothing. But it avoids obvious mistakes.</p>
<p>In ai-memory you can see that pattern in the history. After a big batch of PRs, there are hardening commits from me. One example is <a href="https://github.com/akitaonrails/ai-memory/commit/65682dc"target="_blank" rel="noopener"><code>65682dc</code></a>, &ldquo;fix(audit): address 5 BLOCKING audit findings from today&rsquo;s review,&rdquo; touching OpenAI OAuth, admin API, admission hooks, and the MCP server. Another is the sequence of PRs <a href="https://github.com/akitaonrails/ai-memory/pull/65"target="_blank" rel="noopener"><code>#65</code></a>, <a href="https://github.com/akitaonrails/ai-memory/pull/68"target="_blank" rel="noopener"><code>#68</code></a>, <a href="https://github.com/akitaonrails/ai-memory/pull/70"target="_blank" rel="noopener"><code>#70</code></a>, followed by hardening commits around base path, wikilinks, and strict mode. PR goes in, then audit, then adjustment. That second step is where the difference lives.</p>
<p>In <a href="https://github.com/akitaonrails/ai-memory/pull/77"target="_blank" rel="noopener"><code>#77</code></a>, the auto-scope by session/actor change touched a lot: <code>active_project</code>, hooks router, MCP server, stress tests, multi-user tests. More than 3,800 lines added. I am not going to pretend someone reads that manually line by line with the same consistency after the fifth hour. The agent helps map risk. I use my judgment to decide what needs hardening.</p>
<h2>Regression happens with or without AI<span class="hx:absolute hx:-mt-20" id="regression-happens-with-or-without-ai"></span>
    <a href="#regression-happens-with-or-without-ai" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The rsync case is useful because it exposes a fantasy: the idea that human code was safe and AI code is dangerous.</p>
<p>No. Code is dangerous.</p>
<p>Rust is considered a safe language. And Rust has bugs. Go look at Rust&rsquo;s issue tracker. Zig wants perfection and has bugs. Curl has bugs. Rsync has bugs. Linux has bugs. SQLite has bugs. My code has bugs. Your code has bugs. There is no magical language that produces bug-free software. There never will be.</p>
<p>This is not pessimism. It is a fundamental limit. In computing, we have known for a long time that there is no perfect general verifier for non-trivial semantic properties of programs. Halting problem, Rice&rsquo;s theorem, that kind of thing. You can prove a lot in restricted domains. You can use a better type system. You can use Rust to eliminate entire classes of memory-safety bugs. You can use tests, fuzzing, model checking, static analysis. Good. Use all of it.</p>
<p>But &ldquo;arbitrary software with no bugs&rdquo; is fantasy.</p>
<p>Humans err because of incomplete context, wrong assumptions, pressure, fatigue, lack of tests, lack of real use. AI errs for the same practical reasons: incomplete context, wrong assumptions, training on bad code, poorly specified goals, weak validation. The difference is scale. AI can produce more trash per minute. It can also produce more fixes per minute if you build the process correctly.</p>
<h2>I use it because I use it<span class="hx:absolute hx:-mt-20" id="i-use-it-because-i-use-it"></span>
    <a href="#i-use-it-because-i-use-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Another thing I learned in practice: it is very hard to maintain a project well if you do not use it yourself.</p>
<p>I use ai-memory every day. I use ai-jail every day. I use ai-usagebar every day. I used the <a href="https://github.com/akitaonrails/prettify-manga"target="_blank" rel="noopener">Prettify Manga Reader</a> extension in my real reading. That is why I catch bugs automated tests do not catch.</p>
<p>In Prettify, for example, the commits tell the story. <a href="https://github.com/akitaonrails/prettify-manga/commit/66c6728"target="_blank" rel="noopener"><code>66c6728</code></a> added the night filter. Then came <a href="https://github.com/akitaonrails/prettify-manga/commit/b5bcb4d"target="_blank" rel="noopener"><code>b5bcb4d</code></a>, release 0.2.2, with Kindle Web Reader support, toolbar, shortcuts, and screenshot. Soon after came <a href="https://github.com/akitaonrails/prettify-manga/commit/0e6b7ee"target="_blank" rel="noopener"><code>0e6b7ee</code></a>, release 0.2.3, fixing spread pairing so right-to-left reading stayed correct without messing up chronological order. That came from real use. I was reading, noticed strange behavior, asked the LLM to fix it, tested it, released it.</p>
<p>That is the healthy loop: use it, feel the pain, fix it, test again.</p>
<p>In ai-jail, some contributions came from use cases I would not have prioritized on my own. <a href="https://github.com/akitaonrails/ai-jail/pull/56"target="_blank" rel="noopener"><code>#56</code></a> fixed the PKGBUILD on AUR. <a href="https://github.com/akitaonrails/ai-jail/pull/55"target="_blank" rel="noopener"><code>#55</code></a> forwarded OSC 52 clipboard writes through the alt-screen PTY proxy. <a href="https://github.com/akitaonrails/ai-jail/pull/51"target="_blank" rel="noopener"><code>#51</code></a> recognized Grok as a known agent and documented the machine-id privacy mask. These details show up when other people use the tool in setups different from mine.</p>
<p>In ai-usagebar, this is even clearer. <a href="https://github.com/akitaonrails/ai-usagebar/pull/4"target="_blank" rel="noopener"><code>#4</code></a> added a macOS Keychain fallback for Anthropic credentials. I am on Linux/Omarchy, not macOS. I was not going to find that bug in my daily use. <a href="https://github.com/akitaonrails/ai-usagebar/pull/7"target="_blank" rel="noopener"><code>#7</code></a> fixed reading a custom <code>credentials_path</code> in the widget. Same story: a user with a different config from mine. This is where open source shines: someone scratches their own itch and improves the project for everyone else.</p>
<p>But notice: when I cannot test manually, like macOS and Windows, I depend more on CI. GitHub Actions runs macOS, Windows, Linux. It does not replace real use, but it reduces risk. And when someone who uses that environment opens an issue or PR, that is gold.</p>
<p>Manual testing is still the last line of defense. If you give it up, you are introducing bugs by definition. Automated tests catch what you remembered to specify. Real use catches what you did not even know you needed to specify.</p>
<p>After merging a large set, my final flow is usually:</p>
<blockquote>
  <p>now run <code>bin/deploy</code> to my home server and test it online.</p>
<p>Check health, check whether it still works as before.</p>

</blockquote>
<p>Again: it guarantees nothing. But it avoids breaking the obvious.</p>
<h2>There is no silver bullet<span class="hx:absolute hx:-mt-20" id="there-is-no-silver-bullet"></span>
    <a href="#there-is-no-silver-bullet" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I do not think every project should accept AI PRs. I also do not think every project should ban them. There is no universal rule.</p>
<p>If you are a solo maintainer of a critical library, with no time, no decent CI, no energy to deal with an avalanche of bad PRs, banning AI-assisted contribution may be the right decision for now. Better that than accepting junk and breaking users.</p>
<p>If you maintain a small community and want to teach human contributors, as Zig argues, an anti-AI policy makes sense inside that culture. You are optimizing for contributor formation, not patch throughput.</p>
<p>But if you maintain a project that already gets high volume, that already has CI, that already has tests, that already has users, I think adaptation is inevitable. You will need automated triage. You will need an agent reviewing PRs. You will need a bot summarizing issues. You will need a tool that says &ldquo;this looks like a hallucinated vulnerability report.&rdquo;</p>
<p>AI is imperfect and scales fast. That is exactly why the process has to change.</p>
<h2>My conclusion<span class="hx:absolute hx:-mt-20" id="my-conclusion"></span>
    <a href="#my-conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>AI slop is real. It will get worse before it gets better. There will be garbage PRs. There will be fake security reports. There will be regressions blamed on AI that would have happened with humans too. There will be angry maintainers. There will be users yelling. Normal.</p>
<p>But the direction does not change.</p>
<p>AI-assisted code is here to stay. The percentage of code touched by agents will keep rising. Banning it can work locally, for a while, in one specific community. Across the industry, it is a lost war.</p>
<p>The pragmatic path is to make AI work <strong>for us</strong>. Use AI for triage. Use AI for audits. Use AI to compare diffs. Use AI to find regressions. Use AI to write tests that fail before and pass after. Use AI to do the boring work that wears humans down.</p>
<p>And keep the human decision where it matters.</p>
<p>I have said this several times and I will repeat it: <strong>AI is a mirror</strong>.</p>
<p>If you are sloppy, it accelerates your sloppiness. Your code becomes industrialized AI slop.</p>
<p>If you are a real engineer, it amplifies your engineering. You keep demanding tests, CI, compatibility, migrations, review, clean code, deploy, manual testing. You just do it 10 times faster.</p>
<p>And for companies: if you are thinking, &ldquo;great, now I save money because I do not need to hire as many programmers,&rdquo; I get it. Up to a point. But if you are putting AI into the workflow, then you must strengthen QA. More tests, more review, more validation process, more good people thinking about quality. Skip that and you are screwed. You will trade development cost for production bugs, rework, incidents, and angry customers.</p>
<p>There is no going back to the 100% manual world. Better to stop wasting energy trying to close Pandora&rsquo;s box and start building a decent process around what came out of it.</p>
]]></content:encoded><category>open-source</category><category>coding-agents</category><category>software-engineering</category></item><item><title>Open Source Best Practices with LLMs - The Bare Minimum</title><link>https://akitaonrails.github.io/en/2026/05/30/open-source-best-practices-llm-the-minimum/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/05/30/open-source-best-practices-llm-the-minimum/</guid><pubDate>Sat, 30 May 2026 13:00:00 -0300</pubDate><description>&lt;p&gt;Over the last few months I&amp;rsquo;ve pushed a pile of personal projects to GitHub. &lt;a href="https://github.com/akitaonrails/frank_fbi"target="_blank" rel="noopener"&gt;Frank FBI&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/FrankMega"target="_blank" rel="noopener"&gt;Frank Mega&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener"&gt;Frank Yomik&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/FrankSherlock"target="_blank" rel="noopener"&gt;Frank Sherlock&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/frank_investigator"target="_blank" rel="noopener"&gt;Frank Investigator&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener"&gt;ai-jail&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener"&gt;ai-memory&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener"&gt;ai-usagebar&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener"&gt;ghpending&lt;/a&gt;, and so on. Some in Ruby on Rails, most in Rust, one or two in Flutter. Coded mostly with Claude Code and Codex, riding the wave of my &lt;a href="https://akitaonrails.github.io/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/"&gt;vibe coding marathon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And here&amp;rsquo;s the part nobody mentions when they say &amp;ldquo;I built a project with AI&amp;rdquo;: generating the code is the easy part. The hard part, the thing that separates a repo that&amp;rsquo;s just a pile of code from an actual open source project, is everything that comes &lt;strong&gt;after&lt;/strong&gt; &lt;code&gt;git init&lt;/code&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Over the last few months I&rsquo;ve pushed a pile of personal projects to GitHub. <a href="https://github.com/akitaonrails/frank_fbi"target="_blank" rel="noopener">Frank FBI</a>, <a href="https://github.com/akitaonrails/FrankMega"target="_blank" rel="noopener">Frank Mega</a>, <a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener">Frank Yomik</a>, <a href="https://github.com/akitaonrails/FrankSherlock"target="_blank" rel="noopener">Frank Sherlock</a>, <a href="https://github.com/akitaonrails/frank_investigator"target="_blank" rel="noopener">Frank Investigator</a>, <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a>, <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>, <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>, <a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a>, and so on. Some in Ruby on Rails, most in Rust, one or two in Flutter. Coded mostly with Claude Code and Codex, riding the wave of my <a href="/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/">vibe coding marathon</a>.</p>
<p>And here&rsquo;s the part nobody mentions when they say &ldquo;I built a project with AI&rdquo;: generating the code is the easy part. The hard part, the thing that separates a repo that&rsquo;s just a pile of code from an actual open source project, is everything that comes <strong>after</strong> <code>git init</code>.</p>
<p>I have a strong opinion about this, so let me just plant the flag: no open source project is ready to be published without three things. In order of importance:</p>
<ol>
<li><strong>Installation surface.</strong> The new user has to be able to install and try the tool with the least friction possible. One command, ideally.</li>
<li><strong>Tests and automated CI.</strong> So contributions are easier and there&rsquo;s common ground on what&rsquo;s minimally acceptable to land in the project.</li>
<li><strong>Documentation.</strong> The short, easy-to-read version (the README) and a more detailed set in <code>docs/</code>, so new contributors understand the architectural decisions.</li>
</ol>
<p>Without those three, the way I see it, the project isn&rsquo;t ready. It can have the most brilliant code on earth inside, doesn&rsquo;t matter. If a stranger can&rsquo;t install it, can&rsquo;t trust that whatever they touch won&rsquo;t break everything, and can&rsquo;t understand why things are the way they are, then you don&rsquo;t have an open source project. You have a public dead archive.</p>
<p>And there&rsquo;s a bonus that became an essential part of my workflow: <strong>when all my projects follow the same pattern, I can just tell Claude Code or Codex &ldquo;run the deploy&rdquo; or &ldquo;cut a release,&rdquo; and they can do it.</strong> Because the structure is predictable. <code>bin/deploy</code> does the same thing in every project. The release comes out of a tag. The agent doesn&rsquo;t have to guess anything. Standardization is what makes the automation trustworthy. It looks like fussiness from an organized person, but it&rsquo;s the prerequisite for me to trust, eyes closed, whatever the agent is about to run.</p>
<p>Let me break down the three pillars and show the minimum setup I actually use.</p>
<h2>Pillar 1: The installation surface<span class="hx:absolute hx:-mt-20" id="pillar-1-the-installation-surface"></span>
    <a href="#pillar-1-the-installation-surface" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the most important one and the most neglected. People spend weeks tuning the internal algorithm and then ship a README that says &ldquo;clone the repo and run <code>cargo build --release</code>.&rdquo; So the guy who was curious enough to try it needs to have Rust installed, wait ten minutes for it to compile, and pray no system lib is missing. You just lost 90% of your potential users.</p>
<p>The ideal is to offer <strong>several paths</strong> and let the user pick the one that fits their environment. Look at the install header for ai-jail, my champion of options:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="c1"># Homebrew (macOS or Linux)</span>
</span></span><span class="line"><span class="cl">brew tap akitaonrails/tap <span class="o">&amp;&amp;</span> brew install ai-jail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># AUR (Arch Linux) - prebuilt binary</span>
</span></span><span class="line"><span class="cl">yay -S ai-jail-bin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># cargo (any platform with Rust)</span>
</span></span><span class="line"><span class="cl">cargo install ai-jail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># mise</span>
</span></span><span class="line"><span class="cl">mise use -g github:akitaonrails/ai-jail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Direct binary download</span>
</span></span><span class="line"><span class="cl">curl -fsSL https://github.com/akitaonrails/ai-jail/releases/latest/download/ai-jail-linux-x86_64.tar.gz <span class="p">|</span> tar xz</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Five paths. The Arch user runs <code>yay</code>. The macOS one runs <code>brew</code>. The Rust dev runs <code>cargo install</code>. Whoever uses <a href="https://github.com/jdx/mise"target="_blank" rel="noopener">mise</a> to manage versions pulls it through mise. And whoever just wants the binary downloads the tarball straight from the release. Everyone grabs what they&rsquo;re already used to, nobody&rsquo;s forced to install a whole toolchain just to kick the tires.</p>
<h3>The secret: compile once, repackage many<span class="hx:absolute hx:-mt-20" id="the-secret-compile-once-repackage-many"></span>
    <a href="#the-secret-compile-once-repackage-many" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The gotcha that scares you at first is thinking each package format needs its own build. It doesn&rsquo;t. The trick is to <strong>compile the binary once per architecture, then repackage that same binary into every format.</strong></p>
<p>In my Rust pipeline, the build job produces a tarball with the finished binary and its <code>sha256</code>. The packaging steps that follow (Docker, AUR, Homebrew) <strong>download that already-compiled tarball</strong> instead of recompiling. It cuts CI time, guarantees the byte that goes to AUR is exactly the one that goes to Docker, and kills off that whole class of &ldquo;works in one format, breaks in the other&rdquo; bug.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># Docker job reusing the already-compiled binary</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">docker-amd64</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">build-linux</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">ai-memory-linux-x86_64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">artifacts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Desempacota o binário pré-compilado</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">tar -xzf artifacts/ai-memory-linux-x86_64.tar.gz -C dist/docker/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">docker/build-push-action@v6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">runtime-prebuilt-amd64 </span><span class="w"> </span><span class="c"># inject the binary, don&#39;t recompile</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The AUR job does the same thing: download the tarball, compute the <code>sha256</code>, inject it into the <code>PKGBUILD</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nv">X86_SHA</span><span class="o">=</span><span class="k">$(</span>awk <span class="s1">&#39;{print $1}&#39;</span> artifacts/ai-usagebar-linux-x86_64.tar.gz.sha256<span class="k">)</span>
</span></span><span class="line"><span class="cl">sed -i <span class="s2">&#34;s/^sha256sums_x86_64=.*/sha256sums_x86_64=(&#39;</span><span class="nv">$X86_SHA</span><span class="s2">&#39;)/&#34;</span> packaging/aur/PKGBUILD-bin</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That&rsquo;s the core idea. The binary is the real artifact. RPM, DEB, AppImage, AUR, Homebrew tarball, Docker image, all of it is just <strong>wrapping around the same binary</strong>.</p>
<p>The two snippets above are excerpts. If you want to see the whole thing running, the full build-once-reuse flow (binary compiled once, reused across the Docker and AUR jobs) lives in <a href="https://github.com/akitaonrails/ai-memory/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener">ai-memory&rsquo;s <code>release.yml</code></a>, and the <code>sha256</code> injection into the <code>PKGBUILD</code> is in <a href="https://github.com/akitaonrails/ai-usagebar/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener">ai-usagebar&rsquo;s <code>release.yml</code></a>.</p>
<h3>The menu of formats<span class="hx:absolute hx:-mt-20" id="the-menu-of-formats"></span>
    <a href="#the-menu-of-formats" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every platform is its own world. Here&rsquo;s the minimum worth knowing:</p>
<p><strong>Linux</strong> is the most fragmented. The options, from simplest to most work:</p>
<ul>
<li><strong>Tarball</strong> (<code>.tar.gz</code>): the lowest common denominator. Works on any distro, just unpack it and drop it in <code>PATH</code>. Always offer this one.</li>
<li><strong>AUR</strong> (Arch): two packages, the <code>-bin</code> (prebuilt binary, installs in seconds) and the source one (compiles on the user&rsquo;s machine). I publish both with the <code>KSXGitHub/github-actions-deploy-aur</code> action. The <code>-bin</code> is what everybody uses.</li>
<li><strong>AppImage</strong>: a single executable file that carries all its dependencies inside. Good for desktop apps. Frank Sherlock, which is Tauri, builds the AppImage right in the build and I still GPG-sign it afterward (the signing step is in <a href="https://github.com/akitaonrails/FrankSherlock/blob/master/.github/workflows/release.yml"target="_blank" rel="noopener">its <code>release.yml</code></a>). For a simple binary you can use <code>appimagetool</code>.</li>
<li><strong>RPM and DEB</strong>: for Fedora/openSUSE and Debian/Ubuntu. The tool that saves your life here is <a href="https://github.com/goreleaser/nfpm"target="_blank" rel="noopener">nfpm</a>, which generates both from a single declarative <code>nfpm.yaml</code>, no need to learn the guts of <code>rpmbuild</code> or <code>dpkg-deb</code>. It takes the already-compiled binary and spits out both packages.</li>
</ul>
<p><strong>macOS</strong> has two targets: Apple Silicon (<code>aarch64-apple-darwin</code>) and Intel (<code>x86_64-apple-darwin</code>). You either compile them separately or build a universal binary with <code>lipo</code>. And here lives the platform&rsquo;s biggest headache: <strong>signing and notarization</strong>. Without it, macOS Gatekeeper refuses to open your app. The flow is to decode the P12 certificate, import it into a temporary keychain, sign with <code>codesign --options runtime --timestamp</code>, and notarize:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">codesign --sign <span class="s2">&#34;</span><span class="nv">$APPLE_SIGNING_IDENTITY</span><span class="s2">&#34;</span> --options runtime --timestamp ./meu-binario
</span></span><span class="line"><span class="cl">ditto -c -k meu-binario notarize.zip
</span></span><span class="line"><span class="cl">xcrun notarytool submit notarize.zip <span class="se">\
</span></span></span><span class="line"><span class="cl">  --apple-id <span class="s2">&#34;</span><span class="nv">$APPLE_ID</span><span class="s2">&#34;</span> --password <span class="s2">&#34;</span><span class="nv">$APPLE_PASSWORD</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --team-id <span class="s2">&#34;</span><span class="nv">$APPLE_TEAM_ID</span><span class="s2">&#34;</span> --wait</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This requires a paid Apple Developer account. It&rsquo;s annoying, but it&rsquo;s the price of not throwing an &ldquo;app is damaged&rdquo; error in your user&rsquo;s face. The whole signing-and-notarization job, with the temporary-keychain dance, is in <a href="https://github.com/akitaonrails/ai-jail/blob/master/.github/workflows/release.yml"target="_blank" rel="noopener">ai-jail&rsquo;s <code>release.yml</code></a>.</p>
<p><strong>Windows</strong> is the easiest to build (<code>x86_64-pc-windows-msvc</code>) and the thorniest to sign. A Windows code signing certificate is expensive and bureaucratic, so I, honestly, don&rsquo;t sign. I accept that SmartScreen will throw a warning on first run and I make that clear in the README. For a personal open source project, that&rsquo;s good enough.</p>
<p><strong>Rust crates</strong> (<code>cargo publish</code>): if it&rsquo;s a Rust library or CLI, publishing to <a href="https://crates.io"target="_blank" rel="noopener">crates.io</a> gives you <code>cargo install</code> for free. One line in the pipeline. Tip: make it idempotent, because re-running on an already-published tag errors out. I <code>grep</code> the output for &ldquo;already exists&rdquo; so it doesn&rsquo;t blow up the whole release over that.</p>
<p><strong>Homebrew</strong>: the clean way is to keep your own tap (<code>akitaonrails/homebrew-tap</code>). The pipeline updates the formula with the new URL and the new <code>sha256</code> on every release. The user runs <code>brew tap</code> once and after that it&rsquo;s just <code>brew upgrade</code>.</p>
<p><strong>mise</strong>: <a href="https://github.com/jdx/mise"target="_blank" rel="noopener">mise</a> can install straight from GitHub releases without you configuring anything on your end, as long as your tarballs follow a platform-name convention. You get this path basically for free just by naming your releases well.</p>
<p>Notice a detail: AUR, Homebrew, mise, and the direct download <strong>all consume the same release tarball</strong>. You publish the binaries once, and four different package managers know how to fend for themselves. That&rsquo;s why &ldquo;compile once, repackage many&rdquo; is the golden rule.</p>
<h2>Pillar 2: GitHub Actions, tag-based releases, and the changelog<span class="hx:absolute hx:-mt-20" id="pillar-2-github-actions-tag-based-releases-and-the-changelog"></span>
    <a href="#pillar-2-github-actions-tag-based-releases-and-the-changelog" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The second thing that makes an open source project serious is CI. Forget the &ldquo;build passing&rdquo; badge on the README, the value is in the common ground it creates: when someone sends a pull request, CI runs the tests, the linter, and the security scanner, and you know right away whether that contribution breaks anything. Without it, every PR turns into a tiresome manual negotiation.</p>
<p>On my Rust projects CI runs <code>cargo fmt --check</code>, <code>cargo clippy -D warnings</code>, <code>cargo test</code>, and <code>cargo audit</code>. On the Rails projects it&rsquo;s <code>rubocop</code>, <code>brakeman</code> (security scanner), <code>bundler-audit</code>, and the Minitest suite. <a href="https://github.com/akitaonrails/FrankMD"target="_blank" rel="noopener">FrankMD</a> alone has over 1,800 tests between Ruby and JavaScript. Frank Sherlock clears 300 tests in Rust plus 300 on the frontend. That safety net is what lets me accept a stranger&rsquo;s PR without sweating.</p>
<h3>PR review with an LLM<span class="hx:absolute hx:-mt-20" id="pr-review-with-an-llm"></span>
    <a href="#pr-review-with-an-llm" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The tests and CI are the bottom net. Above it there&rsquo;s a layer that became central to my workflow: using the LLM itself to review the pull requests. Opus and GPT are absurdly good at code review and quality refactoring. Better than me on consistency, because they don&rsquo;t get tired and they don&rsquo;t skim over 200 lines just because it&rsquo;s the fifth review of the day.</p>
<p>I have two prompts I use all the time. The first, for a specific PR that just landed:</p>
<blockquote>
  <p>look at the open PR on github. don&rsquo;t trust the author&rsquo;s description. audit the code thoroughly to see if it actually makes sense. make sure there are no regressions and no drop in code quality. make sure test coverage is adequate. then tell me what you think we should do.</p>

</blockquote>
<p>Notice the &ldquo;don&rsquo;t trust the author&rsquo;s description.&rdquo; That&rsquo;s deliberate. A PR description tells you what the person thought they did, and it doesn&rsquo;t always match what they actually did. The LLM has to read the real code, not the summary.</p>
<p>The second prompt is for after a long coding session or a bunch of PRs merged at once:</p>
<blockquote>
  <p>we touched a lot of code. audit the code those PRs changed, look for dead code, unnecessary duplication, magic hardcoded values that should be constants and/or better documented, missing test coverage, aim for <a href="/en/2026/04/20/clean-code-for-ai-agents/">clean code</a> principles, then check whether the documentation was properly updated.</p>

</blockquote>
<p>With the verdict in hand, I decide. For an incomplete PR, what I do depends on the size and my priority at that moment. If it&rsquo;s something small, I fix it myself right in the PR with an <code>amend</code>, reply explaining what I changed, and then merge and close. When I can merge but can&rsquo;t fix beforehand, I merge and immediately drop a follow-up fix commit. And when it&rsquo;s a big change, I ask the LLM to reply to the PR explaining why we&rsquo;re not merging, with the right direction on what needs to be done.</p>
<p>That&rsquo;s how I closed almost 40 PRs and 20 issues on ai-memory alone, in a couple of days. That volume doesn&rsquo;t happen by hand, and it also can&rsquo;t happen on autopilot.</p>
<p>And this is the point I keep hammering: none of this is blind. I&rsquo;m piloting the LLM toward those goals the whole time. It does the audit, puts the suggestions on the table, and even writes the text of the reply, but the one who decides to merge, fix, or reject is me. The LLM is the tireless reviewer; I&rsquo;m the one who signs off.</p>
<h3>The tag-based trigger<span class="hx:absolute hx:-mt-20" id="the-tag-based-trigger"></span>
    <a href="#the-tag-based-trigger" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The release part is separate from CI. While CI runs on every push and PR, the release fires <strong>only when you push a version tag</strong>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">tags</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s1">&#39;v*.*.*&#39;</span><span class="w">   </span><span class="c"># dispara em v1.2.3, v0.5.0, etc.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">workflow_dispatch</span><span class="p">:</span><span class="w"> </span><span class="c"># permite disparar manualmente também</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The flow for cutting a version becomes this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">git tag v0.5.0
</span></span><span class="line"><span class="cl">git push origin v0.5.0</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And that&rsquo;s it. GitHub Actions notices the tag, fires the release workflow, compiles for the targets, packages everything, signs whatever needs signing, creates the GitHub Release, and publishes to the package managers. I don&rsquo;t touch anything else. In fact that&rsquo;s literally what I tell Claude Code: &ldquo;cut v0.5.0.&rdquo; It runs <code>cargo set-version</code>, updates the CHANGELOG, commits, creates the tag, pushes, and the rest is the pipeline.</p>
<p>The Rust build matrix compiles each target on its native platform:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">include</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-22.04</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">x86_64-unknown-linux-gnu</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-22.04-arm</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">aarch64-unknown-linux-gnu</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">macos-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">aarch64-apple-darwin</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">windows-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">x86_64-pc-windows-msvc</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A cross-compilation gotcha: if you compile ARM inside an x86 machine (via <a href="https://github.com/cross-rs/cross"target="_blank" rel="noopener">cross</a>), you <strong>can&rsquo;t run the tests</strong> for that binary right there, because the architecture doesn&rsquo;t match. The fix is to run tests only on the native target and cross-compile the rest without testing. ai-usagebar does exactly that, x86 native and ARM via <code>cross</code>, in the matrix of <a href="https://github.com/akitaonrails/ai-usagebar/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener">its <code>release.yml</code></a>. And always use a compile cache: <code>Swatinem/rust-cache</code> easily cuts build time in half.</p>
<h3>Release notes and the changelog matter<span class="hx:absolute hx:-mt-20" id="release-notes-and-the-changelog-matter"></span>
    <a href="#release-notes-and-the-changelog-matter" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is where a lot of people slack off, and they shouldn&rsquo;t. When you cut a release, the person thinking about upgrading wants to know <strong>what changed</strong>. &ldquo;v0.5.0&rdquo; says nothing. A changelog says something.</p>
<p>I keep a <code>CHANGELOG.md</code> in the <a href="https://keepachangelog.com/"target="_blank" rel="noopener">Keep a Changelog</a> format, one section per version. And the pipeline automatically extracts the current version&rsquo;s section to paste into the GitHub Release body. A simple <code>awk</code> handles it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">awk -v <span class="nv">ver</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$VERSION</span><span class="s2">&#34;</span> <span class="s1">&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">  BEGIN { hdr = &#34;## [&#34; ver &#34;]&#34; }
</span></span></span><span class="line"><span class="cl"><span class="s1">  index($0, hdr) == 1 { flag=1; next }
</span></span></span><span class="line"><span class="cl"><span class="s1">  flag &amp;&amp; index($0, &#34;## [&#34;) == 1 { exit }
</span></span></span><span class="line"><span class="cl"><span class="s1">  flag { print }
</span></span></span><span class="line"><span class="cl"><span class="s1">&#39;</span> CHANGELOG.md &gt; changelog_section.md</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That <code>awk</code> is the same one that runs on the ai-usagebar release (again in <a href="https://github.com/akitaonrails/ai-usagebar/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener">its <code>release.yml</code></a>, which is my most polished one on this front). Then, after the changelog, I append the install instructions and the <code>sha256</code> checksums for each artifact. The result is a GitHub Release that explains itself: what changed, how to install it, and how to verify the integrity of the download. The user reads it and decides whether to upgrade. That&rsquo;s the kind of care that makes a stranger trust your project.</p>
<h2>Pillar 3: Real deployment, no fuss<span class="hx:absolute hx:-mt-20" id="pillar-3-real-deployment-no-fuss"></span>
    <a href="#pillar-3-real-deployment-no-fuss" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The projects that run as a service (the Rails ones, mainly) have to go somewhere. And here I go against the hype. No Kubernetes. No Kamal. No three-stage deploy pipeline with manual approval.</p>
<p>I have a home server. A <a href="/en/2026/03/31/migrating-my-home-server-with-claude-code/">Minisforum MS-S1 Max running openSUSE MicroOS</a> that I migrated recently, with a <a href="https://github.com/go-gitea/gitea"target="_blank" rel="noopener">Gitea</a> acting as a private Docker registry on port 3007. For a solo developer with a simple home server, that&rsquo;s more than enough. All that cluster-orchestration ceremony is solving a problem I don&rsquo;t have.</p>
<p>The whole deploy fits in a single <code>bin/deploy</code>. It does three things: builds the image, pushes it to the registry, and SSHes into the server to bring up the new version:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Config comes from a .gitignored file, outside the repo</span>
</span></span><span class="line"><span class="cl"><span class="nb">source</span> <span class="s2">&#34;</span><span class="k">$(</span>dirname <span class="s2">&#34;</span><span class="nv">$0</span><span class="s2">&#34;</span><span class="k">)</span><span class="s2">/../config/deploy.env&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">IMAGE</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">REGISTRY_HOST</span><span class="si">}</span><span class="s2">:</span><span class="si">${</span><span class="nv">REGISTRY_PORT</span><span class="si">}</span><span class="s2">/akitaonrails/frank_fbi:latest&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;==&gt; Buildando a imagem...&#34;</span>
</span></span><span class="line"><span class="cl">docker build -t <span class="s2">&#34;</span><span class="nv">$IMAGE</span><span class="s2">&#34;</span> .
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;==&gt; Empurrando pro registry...&#34;</span>
</span></span><span class="line"><span class="cl">docker push <span class="s2">&#34;</span><span class="nv">$IMAGE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;==&gt; Subindo no servidor...&#34;</span>
</span></span><span class="line"><span class="cl">ssh <span class="s2">&#34;</span><span class="si">${</span><span class="nv">DEPLOY_USER</span><span class="si">}</span><span class="s2">@</span><span class="si">${</span><span class="nv">DEPLOY_HOST</span><span class="si">}</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  <span class="s2">&#34;cd </span><span class="si">${</span><span class="nv">REMOTE_DIR</span><span class="si">}</span><span class="s2"> &amp;&amp; \
</span></span></span><span class="line"><span class="cl"><span class="s2">   docker compose pull &amp;&amp; \
</span></span></span><span class="line"><span class="cl"><span class="s2">   docker compose down --remove-orphans &amp;&amp; \
</span></span></span><span class="line"><span class="cl"><span class="s2">   docker compose up -d&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That&rsquo;s it. <code>build</code>, <code>push</code>, <code>ssh</code> with <code>pull</code>, <code>down</code>, <code>up</code>. Four commands on the remote server, chained in a single SSH. No agent running over there, no webhook, no control panel. The server has a <code>docker-compose.production.yml</code> pointing at the <code>:latest</code> image from the registry, and the <code>pull</code> brings the new version down.</p>
<p>Notice the sensitive data lives in a <code>config/deploy.env</code> that <strong>doesn&rsquo;t go into Git</strong>. The repo only carries the <code>config/deploy.env.example</code>, with the structure and fake values. This &ldquo;versioned example, real one ignored&rdquo; pattern repeats in every project of mine, and it&rsquo;s what lets the project be public without leaking the host, user, or path of my server.</p>
<p>The image itself comes from a multi-stage Dockerfile. The build stage installs the compilation tools, builds everything, and the final stage copies only the result into a lean image, running as a non-root user. The production compose swaps <code>build:</code> for <code>image:</code>, points the volumes at the server&rsquo;s persistent paths (<code>/var/opt/docker/...</code>), and uses <code>restart: always</code> to bring everything back up if the server reboots.</p>
<p>And again, the beauty of standardization: since <strong>every</strong> project of mine has this same <code>bin/deploy</code>, I can tell Claude Code &ldquo;deploy Frank FBI&rdquo; and it knows exactly what to run. I don&rsquo;t have to remember a single command. The tool is the executable documentation of the process.</p>
<h2>The lesson: nobody cares about your stack<span class="hx:absolute hx:-mt-20" id="the-lesson-nobody-cares-about-your-stack"></span>
    <a href="#the-lesson-nobody-cares-about-your-stack" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now the part I most wanted to write, and the one worth more than all the YAML snippets above.</p>
<p>Most people, when they go to present a project, focus everything on the technology. &ldquo;Check out my brand-new vector database.&rdquo; &ldquo;Check out my last-gen reactive framework.&rdquo; &ldquo;I used such-and-such microservices architecture.&rdquo; And they fill the top of the README with that: the dependency list, the component diagram, the stack.</p>
<p>Nobody cares.</p>
<p>Seriously. The user who lands on your README doesn&rsquo;t want to know which database you used. They want to know <strong>what problem this solves for them</strong>. Implementation detail doesn&rsquo;t belong at the top of the README. It belongs in <code>docs/</code>, for whoever&rsquo;s going to contribute. In the README, what matters is the use case.</p>
<p>Look at the difference. &ldquo;MCP server in Rust with FTS5 and optional LLM consolidation&rdquo; says nothing to anybody. Now &ldquo;long-term memory shared across Claude Code, Codex, and Cursor, with handoff between sessions&rdquo; — that one the guy gets instantly, because it&rsquo;s the pain he has. Both describe ai-memory. One talks about technology, the other talks about the problem it solves.</p>
<p>The use case is the single most important thing about the whole project. Before writing a line of code, the right question is &ldquo;what problem does this solve, and for whom?&rdquo; If you can&rsquo;t answer that in one sentence, you&rsquo;re building a <strong>solution looking for a problem</strong>. And a solution looking for a problem is, in practice, a solution that solves nothing. Doesn&rsquo;t matter how elegant the code is on the inside.</p>
<p>The UX layer, the surface the user touches, is worth far more than the internal engineering. A project with mediocre technology that&rsquo;s trivial to install, that clearly states what problem it solves, and that has honest documentation, goes further than a brilliant project nobody can run. Every time.</p>
<p>So the minimum, the real minimum for an open source project, is this: easy install, CI that gives you confidence, documentation that starts from the problem. The pretty algorithm comes way down the priority list. The three pillars of this post exist to serve one thing, which is the experience of whoever shows up from outside. Get that right first. The rest is implementation detail.</p>
]]></content:encoded><category>open-source</category><category>software-engineering</category><category>devops</category></item><item><title>How to Contribute to the AkitaOnRails Blog Using Docker</title><link>https://akitaonrails.github.io/en/2025/08/29/how-to-contribute-to-the-akitaonrails-blog-using-docker/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2025/08/29/how-to-contribute-to-the-akitaonrails-blog-using-docker/</guid><pubDate>Fri, 29 Aug 2025 22:37:16 -0300</pubDate><description>&lt;p&gt;Contributing to open source projects can be a pain when you have to set up a complex development environment. On the AkitaOnRails blog, that used to mean installing Hugo Extended, Go, Ruby, and all their dependencies. Now we have a much simpler solution: &lt;strong&gt;Docker&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The Problem&lt;span class="hx:absolute hx:-mt-20" id="the-problem"&gt;&lt;/span&gt;
&lt;a href="#the-problem" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Before, to contribute to the blog you had to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install Hugo Extended&lt;/li&gt;
&lt;li&gt;Install Go&lt;/li&gt;
&lt;li&gt;Install Ruby&lt;/li&gt;
&lt;li&gt;Set up all the dependencies&lt;/li&gt;
&lt;li&gt;Generate the post index manually&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This created barriers for new contributors and could cause conflicts with other installations on the system. A nightmare.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Contributing to open source projects can be a pain when you have to set up a complex development environment. On the AkitaOnRails blog, that used to mean installing Hugo Extended, Go, Ruby, and all their dependencies. Now we have a much simpler solution: <strong>Docker</strong>.</p>
<h2>The Problem<span class="hx:absolute hx:-mt-20" id="the-problem"></span>
    <a href="#the-problem" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before, to contribute to the blog you had to:</p>
<ol>
<li>Install Hugo Extended</li>
<li>Install Go</li>
<li>Install Ruby</li>
<li>Set up all the dependencies</li>
<li>Generate the post index manually</li>
</ol>
<p>This created barriers for new contributors and could cause conflicts with other installations on the system. A nightmare.</p>
<h2>The Solution: Docker<span class="hx:absolute hx:-mt-20" id="the-solution-docker"></span>
    <a href="#the-solution-docker" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now all you need is Docker and Docker Compose. Everything else runs inside isolated containers.</p>
<h3>Quick Setup<span class="hx:absolute hx:-mt-20" id="quick-setup"></span>
    <a href="#quick-setup" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Clone the repository</span>
</span></span><span class="line"><span class="cl">git clone https://github.com/akitaonrails/akitaonrails.github.io.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> akitaonrails.github.io
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Start the environment</span>
</span></span><span class="line"><span class="cl">./scripts/dev.sh start
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Open the blog</span>
</span></span><span class="line"><span class="cl">open http://localhost:1313</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done! The blog is running and you can start contributing.</p>
<h2>Useful Commands<span class="hx:absolute hx:-mt-20" id="useful-commands"></span>
    <a href="#useful-commands" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The project includes scripts that make development easier:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># See all available commands</span>
</span></span><span class="line"><span class="cl">./scripts/dev.sh <span class="nb">help</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create a new post</span>
</span></span><span class="line"><span class="cl">./scripts/dev.sh new-post <span class="s2">&#34;Título do Meu Post&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># View server logs</span>
</span></span><span class="line"><span class="cl">./scripts/dev.sh logs
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Generate the post index</span>
</span></span><span class="line"><span class="cl">./scripts/dev.sh generate-index
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Stop the environment</span>
</span></span><span class="line"><span class="cl">./scripts/dev.sh stop</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Creating a Post<span class="hx:absolute hx:-mt-20" id="creating-a-post"></span>
    <a href="#creating-a-post" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Creating a new post is dead simple:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./scripts/dev.sh new-post <span class="s2">&#34;Como Contribuir no Blog do AkitaOnRails&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The script automatically:</p>
<ul>
<li>Creates the directory structure with the current date</li>
<li>Generates an <code>index.md</code> file with basic front matter</li>
<li>The Hugo server reloads automatically</li>
</ul>
<h2>Structure of a Post<span class="hx:absolute hx:-mt-20" id="structure-of-a-post"></span>
    <a href="#structure-of-a-post" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The created file will have this structure:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">title: &#34;Título do Post&#34;
</span></span><span class="line"><span class="cl">date: &#34;2025-08-29&#34;
</span></span><span class="line"><span class="cl">draft: false
</span></span><span class="line"><span class="cl">description: &#34;Descrição do post&#34;
</span></span><span class="line"><span class="cl">tags: [tag1, tag2]
</span></span><span class="line"><span class="cl">categories: [categoria]
</span></span><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Conteúdo do post aqui...</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Advantages of Docker<span class="hx:absolute hx:-mt-20" id="advantages-of-docker"></span>
    <a href="#advantages-of-docker" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>For Contributors<span class="hx:absolute hx:-mt-20" id="for-contributors"></span>
    <a href="#for-contributors" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Fast setup</strong>: Docker is the only requirement</li>
<li><strong>Isolated environment</strong>: Stays out of the way of your local system</li>
<li><strong>Hot reload</strong>: Changes show up automatically</li>
<li><strong>Reproducible</strong>: Works the same way for everyone</li>
</ul>
<h3>For the Project<span class="hx:absolute hx:-mt-20" id="for-the-project"></span>
    <a href="#for-the-project" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Fewer issues</strong>: Consistent environment</li>
<li><strong>More contributors</strong>: Lower barrier to entry</li>
<li><strong>Maintenance</strong>: Easy to update dependencies</li>
</ul>
<h2>How It Works<span class="hx:absolute hx:-mt-20" id="how-it-works"></span>
    <a href="#how-it-works" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The Docker environment includes:</p>
<ul>
<li><strong>Hugo Extended</strong>: Static site generator</li>
<li><strong>Go</strong>: For Hugo modules</li>
<li><strong>Ruby</strong>: For the index generation script</li>
<li><strong>Volumes</strong>: For hot reload of files</li>
</ul>
<p>The <code>docker-compose.yml</code> maps the local directories into the container, so when you edit a file, Hugo detects the change and reloads automatically.</p>
<h2>Local Development (Alternative)<span class="hx:absolute hx:-mt-20" id="local-development-alternative"></span>
    <a href="#local-development-alternative" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you prefer to skip Docker, you can still install everything locally:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Generate the index</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> content <span class="o">&amp;&amp;</span> ruby generate_index.rb
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Run the server</span>
</span></span><span class="line"><span class="cl">hugo server --logLevel debug --disableFastRender -p <span class="m">1313</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>But Docker is way more practical!</p>
<h2>Next Steps<span class="hx:absolute hx:-mt-20" id="next-steps"></span>
    <a href="#next-steps" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ol>
<li><strong>Test the environment</strong>: Run <code>./scripts/dev.sh start</code></li>
<li><strong>Create a post</strong>: Use <code>./scripts/dev.sh new-post</code></li>
<li><strong>Explore the code</strong>: See how to customize layouts</li>
<li><strong>Contribute</strong>: Open a Pull Request</li>
</ol>
<hr>
<p><strong>Tip</strong>: The Docker environment automatically saves your changes and reloads the server. Just edit the files and watch the changes in real time! 🚀</p>
]]></content:encoded><category>open-source</category><category>containers</category><category>tutorials</category></item><item><title>3 Months of GitLab. The Hybrid-SaaS Era</title><link>https://akitaonrails.github.io/en/2016/11/16/3-months-of-gitlab-the-hybrid-saas-era/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/11/16/3-months-of-gitlab-the-hybrid-saas-era/</guid><pubDate>Wed, 16 Nov 2016 16:44:00 -0200</pubDate><description>&lt;p&gt;If you didn&amp;rsquo;t already, maybe it&amp;rsquo;s a good idea to read my previous post on &lt;a href="https://about.gitlab.com/2016/08/04/moving-to-gitlab-yes-its-worth-it/"target="_blank" rel="noopener"&gt;Moving to GitLab! Yes, it&amp;rsquo;s worth it!&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My impressions stem from very specific circumstances, so this is not to be read as a general recommendation for every situation. For example, I didn&amp;rsquo;t review GitLab&amp;rsquo;s hosted options, which may be more compatible with circumstances different than mine.&lt;/p&gt;
&lt;p&gt;In my case, the move to GitLab was part of an internal company strategy to have more control over our own data. In that strategy we also moved from using Slack to Mattermost, and from using Pivotal Tracker to my own open source alternative called &lt;a href="https://github.com/Codeminer42/cm42-central"target="_blank" rel="noopener"&gt;Central&lt;/a&gt;, among other things.&lt;/p&gt;</description><content:encoded><![CDATA[<p>If you didn&rsquo;t already, maybe it&rsquo;s a good idea to read my previous post on <a href="https://about.gitlab.com/2016/08/04/moving-to-gitlab-yes-its-worth-it/"target="_blank" rel="noopener">Moving to GitLab! Yes, it&rsquo;s worth it!</a>.</p>
<p>My impressions stem from very specific circumstances, so this is not to be read as a general recommendation for every situation. For example, I didn&rsquo;t review GitLab&rsquo;s hosted options, which may be more compatible with circumstances different than mine.</p>
<p>In my case, the move to GitLab was part of an internal company strategy to have more control over our own data. In that strategy we also moved from using Slack to Mattermost, and from using Pivotal Tracker to my own open source alternative called <a href="https://github.com/Codeminer42/cm42-central"target="_blank" rel="noopener">Central</a>, among other things.</p>
<p>Before the migration, I had dozens of active projects over GitHub and lots of archived ones at Bitbucket. I&rsquo;m the kind that hates to lose data, so I keep redundant backups and try to never erase anything.</p>
<p>I moved almost everything over to my own GitLab server and this is almost <strong>200 repositories</strong>, spread in 4 groups, with almost 80 active users. This accounts for more than 13,500 notes and over 5,200 Merge Requests already, and over 2,500 builds in the CI, and the internal Sidekiq controlling everything has over 51,000 jobs processed.</p>
<p>In the last 3 months since the migration, I am paying a Digital Ocean bill of around $140 every month for the exact infrastructure I described in the previous article, with a separated box for the GitLab Core, the CI Runner, the CI Docker Registry Mirror, the CI Cache server and disposable machines for parallel builds, controlled by the Runner.</p>
<p>Although the reduction in cost is welcome, the whole endeavor was not done because of it. I could easily pay double or triple just for the convenience, but the underlying strategy is more important in this case.</p>
<p>My company has over 60 developers, working from our own offices in 6 different cities in Brazil (no freelancers and no home-office), communicating daily over Mattermost, Code Reviewing through GitLab&rsquo;s Merge Requests, having immediate automated tests feedback from GitLab CI, and project management through our own Central application.</p>
<p>The only piece that is currently missing is a good static code analysis tool. We heavily rely on Code Climate, which I strongly believe is one of the best out there from our own experience.</p>
<p>I was about to start an endeavor to build a simplified OSS version to integrate into GitLab CI&rsquo;s, but <a href="http://blog.codeclimate.com/blog/2016/10/06/series-a-and-community-edition/"target="_blank" rel="noopener">Bryan Helmkamp recently announced</a> that they would release their own &ldquo;Community Edition&rdquo; version of Code Climate in the next few months.</p>
<p>This is exactly the missing piece in my stack, and it will make my strategy move faster for next year.</p>
<h3>Hybrid-SaaS Era<span class="hx:absolute hx:-mt-20" id="hybrid-saas-era"></span>
    <a href="#hybrid-saas-era" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the past 5 to 10 years there was a fast move towards 3rd party &ldquo;micro-services&rdquo; structure. And this is really great as it allowed many small companies or even independent developers to tap into technology that made them not only move faster, but with increasingly more quality in their delivery.</p>
<p>It&rsquo;s now super easy to have top-notch upload and storage service through tools like Cloudinary.</p>
<p>Also very easy to have top-notch relational database, with replication and scalability, such as Heroku Postgres or AWS RDS.</p>
<p>Project management as a service with Pivotal Tracker, Trello.</p>
<p>Communication as a service with Slack, Hangout, etc.</p>
<p>Knowledge Management as a service with GitHub, Bitbucket, etc.</p>
<p>So now many tech companies are a mashup of several different 3rd party services.</p>
<p>My small beef is that our entire knowledge, experience, portfolio is spread across a dozen or more opaque services, completely out of our control and depending on each company&rsquo;s (or their investors) whim.</p>
<p>Don&rsquo;t get me wrong, I am not against using those services, on the contrary. I use several of them and I will continue to use many of them for the foreseeable future. Some endeavors would not even be possible without the efficiency of this sample of a technology-based free market.</p>
<p>But every now and then you reach a tipping point where it becomes important to have more control over your own data, your own identity. Not only for pure ownership but also to be able to use this data with better intent.</p>
<p>And I believe that at that point we should have an option that doesn&rsquo;t cost a couple of limbs to replicate.</p>
<p>Before an option such as GitLab, we were either limited to choose between walled-gardens such as GitHub or Bitbucket or you could invest a ton of resources trying to use small open sourced components to try to build your own. With GitLab we now have the option to make a smooth transition to its hosted option, so we don&rsquo;t have to deal with infrastructure maintenance or we can choose to have full control. And the users will not suffer in the process.</p>
<p>Which is why I believe that the best SaaS to endure the next decade will start to go into <strong>Hybrid-mode</strong>: having a commercial, usually &ldquo;cheaper&rdquo;, hosted option, and a DIY (do-it-yourself) OSS version.</p>
<p>GitLab is like that. Mattermost is like that. Now Code Climate is getting like that.</p>
<p>In that option, companies like GitLab have a win-win situation. Many more people and companies can contribute towards making a mature and robust platform that everybody enjoys using, and at the same time, each participant can extend it to their own particular plans. GitLab can have a sustainable business model serving the long tail of companies and developers that want a reasonably affordable hosted service while the top 20% can pursue more specific endeavors using the same technology.</p>
<p>That way we remove the discussion of confidentiality, the way companies treat our data, and we move forward into more productive actions such as building a tool that benefits both the external public and each other&rsquo;s internal plans.</p>
<p>Walled gardens are here to stay. Releasing integration — while opaque — public APIs is not enough. It&rsquo;s very exciting to see those new options arising to fill this gap. The OSS environment along with a sustainable business model makes sense. And I hope to continue to see more and more competitors to closed services following the Hybrid model in the near future.</p>
<p>Why go through the trouble to install, maintain and tweak open sourced alternatives to well-established hosted (albeit opaque) services? I believe it&rsquo;s more than a discussion over convenience, maintenance and cutting costs. We should start small, less risky, but as we grow we should be able to take control back. But we usually can&rsquo;t get out of walled gardens without a significant - and sometimes impossible - investment in reinventing the wheel. We always had the small open sourced components that those services are built on, but to go from those small components to a full-featured system, it&rsquo;s an unrealistic path.</p>
<p>With this possible trend of post-SaaS, or Hybrid-SaaS as I call it, we may have just gained the missing link to go from just convenience to full control without the inherent costs and risks chasm.</p>
]]></content:encoded><category>version-control</category><category>open-source</category><category>business</category></item><item><title>[Off-Topic] Free Software: An Exercise in CAPITALISM</title><link>https://akitaonrails.github.io/en/2016/04/22/off-topic-free-software-an-exercise-in-capitalism/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/04/22/off-topic-free-software-an-exercise-in-capitalism/</guid><pubDate>Fri, 22 Apr 2016 15:30:00 -0300</pubDate><description>&lt;p&gt;A sentence from &lt;a href="https://akitaonrails.github.io/en/2016/04/20/off-topic-se-voce-precisa-de-validacao-provavelmente-esta-errado"&gt;my previous article&lt;/a&gt; raised some eyebrows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;The foundation of that is the open source world: the biggest capitalist experiment in software and a living example of what a Laissez-faire Free Market looks like. The best place to maintain and improve technology commodities.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The confusion comes from the word &amp;ldquo;free&amp;rdquo;. Because of the freedom principles of Free Software, a lot of people associate open source with one big &amp;ldquo;socialist&amp;rdquo; experiment. My thesis is the opposite: free software is the most capitalist thing in software. No government regulates it, no agency protects bad projects, every exchange is voluntary, and competition decides who survives. No sector of the real economy works like that; the closest historical period was late 19th century America, before the Federal Reserve and the federal income tax.&lt;/p&gt;</description><content:encoded><![CDATA[<p>A sentence from <a href="/en/2016/04/20/off-topic-se-voce-precisa-de-validacao-provavelmente-esta-errado">my previous article</a> raised some eyebrows:</p>
<blockquote>
  <p>&ldquo;The foundation of that is the open source world: the biggest capitalist experiment in software and a living example of what a Laissez-faire Free Market looks like. The best place to maintain and improve technology commodities.&rdquo;</p>

</blockquote>
<p>The confusion comes from the word &ldquo;free&rdquo;. Because of the freedom principles of Free Software, a lot of people associate open source with one big &ldquo;socialist&rdquo; experiment. My thesis is the opposite: free software is the most capitalist thing in software. No government regulates it, no agency protects bad projects, every exchange is voluntary, and competition decides who survives. No sector of the real economy works like that; the closest historical period was late 19th century America, before the Federal Reserve and the federal income tax.</p>
<p>Matt Asay wrote on CNET, in <a href="http://www.cnet.com/news/open-source-its-about-capitalism-not-freebies/"target="_blank" rel="noopener">&ldquo;Open source: It&rsquo;s about capitalism, not freebies&rdquo;</a>:</p>
<blockquote>
  <p>&ldquo;The secret is to use open source as a means to an end, not the end itself. Open source is a means to cheap distribution, a way to get software into the hands of would-be buyers at little to no cost. It&rsquo;s a way to make the software experience social and less risky, because users can try before they buy and because they can tailor (or pay someone else to tailor) software to their needs for a lower cost than proprietary software affords.&rdquo;</p>

</blockquote>
<p>And he was even more blunt in <a href="http://web.archive.org/web/20211023100641/https://www.cnet.com/news/sorry-socialists-open-source-is-a-capitalists-game/"target="_blank" rel="noopener">&ldquo;Sorry, socialists: Open source is a capitalist&rsquo;s game&rdquo;</a>:</p>
<blockquote>
  <p>&ldquo;[Sarah] Grey writes that &rsquo;there are alternatives to capitalism&rsquo;. She&rsquo;s right. Unfortunately, open source isn&rsquo;t one of them. Open source is the essence of Free Market Capitalism.&rdquo;</p>

</blockquote>
<h3>Definitions, so nobody fights a strawman<span class="hx:absolute hx:-mt-20" id="definitions-so-nobody-fights-a-strawman"></span>
    <a href="#definitions-so-nobody-fights-a-strawman" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>First, the terms I&rsquo;m using. Capitalism is private ownership of the means of production, with voluntary exchanges between the owners of that property. A Free Market is those exchanges carried out with no coercion and no regulator: supply, demand, and prices stay in the hands of the participants.</p>
<p>Socialism, in the classical sense, is state or collective ownership of the means of production. Public healthcare and free education in a market economy are welfare policies, not socialism. The target of this text is the model where the State owns production.</p>
<p>With these definitions, defending classical socialism and defending individual liberty are opposite positions: the first requires subordinating everyone&rsquo;s property and choices to a central authority.</p>
<h3>Free software is private property under a license<span class="hx:absolute hx:-mt-20" id="free-software-is-private-property-under-a-license"></span>
    <a href="#free-software-is-private-property-under-a-license" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Open source code has an owner, always. Copyright belongs to the authors, and using, copying, or modifying that code is only possible because the owner granted a license. Without a license, nobody has any right over someone else&rsquo;s code, as Jeff Atwood pointed out in <a href="http://blog.codinghorror.com/pick-a-license-any-license/"target="_blank" rel="noopener">&ldquo;Pick a License, Any License&rdquo;</a>:</p>
<blockquote>
  <p>&ldquo;Because I did not explicitly indicate a license, I declared an implicit copyright without explaining how others could use my code. Since the code is unlicensed, I could theoretically assert copyright at any time and demand that people stop using my code. Experienced developers won&rsquo;t touch unlicensed code because they have no legal right to use it.&rdquo;</p>

</blockquote>
<p>There&rsquo;s a practical test for this property: the owner can pull the code out of circulation whenever they want. In March 2016, Azer Koçulu unpublished his packages from npm, including the tiny left-pad, after a name dispute with the Kik app. Thousands of builds broke that same day, as <a href="http://arstechnica.com/information-technology/2016/03/rage-quit-coder-unpublished-17-lines-of-javascript-and-broke-the-internet/"target="_blank" rel="noopener">Ars Technica reported</a>. The source code stayed on GitHub; what he removed was the distribution from the registry.</p>
<p>Agreeing with Koçulu or not is irrelevant. The package was his property, and the decision to remove it was his. The interesting part came after: nobody got arrested, no regulator stepped in. npm restored the broken package and changed its <a href="http://blog.npmjs.org/post/141905368000/changes-to-npms-unpublish-policy"target="_blank" rel="noopener">unpublish policy</a>. The market absorbed the shock and grew antibodies, without taking away anyone&rsquo;s right to walk out.</p>
<p>The Ruby community lived through a smaller version of this in 2009, when _why deleted his projects and vanished, <a href="/en/2012/09/07/_why-ruby-dramas-and-dynamiting-courtlandt/">as I wrote here</a>.</p>
<p>When the disagreement is internal, the exit mechanism is the fork: whoever disagrees clones the project and competes with the original. That&rsquo;s what happened with io.js, born as a fork of Node.js in 2014 and merged back in 2015 under the newly created Node.js Foundation, once negotiation made sense. History has plenty of thriving forks: WebKit from KHTML, LibreOffice from OpenOffice.org, MariaDB from MySQL, X.Org from XFree86. And there are derivatives that outgrew their origins, like Ubuntu from Debian.</p>
<p>A fork is voting with your feet. It&rsquo;s expensive, because it means maintaining an entire project, and that&rsquo;s exactly why it only thrives when the motivation is real.</p>
<h3>Competition implies the right to fail<span class="hx:absolute hx:-mt-20" id="competition-implies-the-right-to-fail"></span>
    <a href="#competition-implies-the-right-to-fail" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In a market with no regulator, nobody keeps a bad project artificially alive. For every PostgreSQL out there, dozens of databases tried and died. For every relevant Linux distro, hundreds became footnotes. That&rsquo;s a sign of health: selection is working.</p>
<p>The justice of this process is blind. Code doesn&rsquo;t carry its author&rsquo;s biography, and the market hands out no medals for good intentions. A project survives if it convinces users and contributors of its technical merit, and dies if it doesn&rsquo;t.</p>
<p>Opening the code, by the way, saves no one. Nokia finished open-sourcing Symbian in 2010, when the platform was already losing ground to the iPhone and Android. The gesture changed nothing: too little, too late.</p>
<p>I compared this process to natural selection in an <a href="http://www.akitaonrails.com/2010/07/01/screencast-entenda-software-da-maneira-correta"target="_blank" rel="noopener">old screencast</a> (in Portuguese). The software that adapts best to the demands of its environment is the one that reproduces the most, as users and contributors. The graveyard of dead projects proves selection exists and works.</p>
<p>And the landscape shifts all the time. Apache HTTP ceded ground to NGINX. Firefox lost a huge slice to Chrome. Perl ceded to Python and to newer languages like Go. MySQL lost prestige among developers to PostgreSQL, faced the NoSQL wave, and still gained a competing fork, MariaDB, after the Oracle acquisition. None of these projects had squatters&rsquo; rights to the throne.</p>
<h3>The programmer pays to participate<span class="hx:absolute hx:-mt-20" id="the-programmer-pays-to-participate"></span>
    <a href="#the-programmer-pays-to-participate" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The free software market has a curious inversion of values. At a company, the programmer gets paid money to write proprietary code. In a well-known free project, it&rsquo;s the programmer who &ldquo;pays&rdquo;, with their time and skill, to get code accepted. In return they get reputation, learning, portfolio, and yes, a bit of vanity. It&rsquo;s a voluntary exchange that benefits both sides, like any other.</p>
<p>&ldquo;Price&rdquo; here isn&rsquo;t measured only in money. Value is anything with supply and demand, and competition sets the price. The currency of this market is technical competence demonstrated in public.</p>
<p>That has a hard consequence: convincing others is part of the game. If your idea has value and still nobody adopts it, the most likely explanation is the idea or how you presented it, not the audience&rsquo;s stupidity. Blaming the audience is the fastest way to devalue your own cause.</p>
<h3>The paradox of &ldquo;socialist&rdquo; free software<span class="hx:absolute hx:-mt-20" id="the-paradox-of-socialist-free-software"></span>
    <a href="#the-paradox-of-socialist-free-software" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Picture the opposite model: the software world under classical socialism, with production controlled by a central authority.</p>
<p>Without individual ownership of projects, competition ends. A bad project that serves the controllers&rsquo; agenda stays alive, even when a technically superior alternative exists. Choice leaves the hands of the users and moves to the hands of the controllers. There would be no left-pad accidents, and the price of that would be a huge catalog of derelict software nobody wants to use.</p>
<p>Without the individual benefit of exchange, volunteering ends. No competent programmer would donate their best hours without reputation, learning, or freedom in return. And if contribution becomes a mandatory quota decreed in the name of the &ldquo;social good&rdquo;, everyone will do the bare minimum to fill the quota. Soviet production worked exactly like that in pretty much every sector, with the results we all know.</p>
<p>Without competition, innovation ends. Innovation is born from an individual&rsquo;s will to solve their own problem their own way. Eric Raymond opened <a href="http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/"target="_blank" rel="noopener">&ldquo;The Cathedral and the Bazaar&rdquo;</a> with that idea:</p>
<blockquote>
  <p>&ldquo;Every good work of software starts by scratching a developer&rsquo;s personal itch.&rdquo;</p>

</blockquote>
<p>Innovation is also transgressive, because it makes entire professions obsolete. Travel agencies nearly vanished once buying tickets online became trivial. Video rental stores died with streaming. Uber squeezed cab drivers, Airbnb squeezed hotels. Whoever stayed stuck in the old model suffered, and the world moved on.</p>
<p>Software was the same. The GNU Hurd folks didn&rsquo;t celebrate when Linux exploded. Nokia found no humor in Android. MySQL doesn&rsquo;t root for PostgreSQL. Whoever resists the market&rsquo;s dynamics gets left behind. Harsh, and absolutely fair.</p>
<h3>The dystopia of the protected monopoly<span class="hx:absolute hx:-mt-20" id="the-dystopia-of-the-protected-monopoly"></span>
    <a href="#the-dystopia-of-the-protected-monopoly" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Proprietary software can be good or bad; the problem shows up when it becomes a protected monopoly. 1990s Microsoft was a de facto monopoly. We can argue forever about whether the Department of Justice ruling was fair, but the decisive blow to the monopoly came from the market: free software, with GNU and Linux, and then the commercial internet, which took the platform monopoly away from Windows.</p>
<p>Imagine an alternate future where Microsoft convinces the US government that Windows is essential to national security and deserves permanent protection. Everything would have stopped. To this day we&rsquo;d be using a 100 MHz Pentium running some Windows 98 derivative, on dial-up, because &ldquo;nobody needs more than that&rdquo;.</p>
<p>That&rsquo;s the logic of handing the market&rsquo;s decisions to a central authority: don&rsquo;t invent email, it will hurt the mail carriers; don&rsquo;t build websites, it will hurt the printing plants; don&rsquo;t create free software, it will hurt the government&rsquo;s programmers. Every dictator uses the same speech, &ldquo;for the good of the people&rdquo;, and every speech of &ldquo;for the good of the people, whatever the means&rdquo; ends in the same place.</p>
<h3>Tyranny and the end of free software<span class="hx:absolute hx:-mt-20" id="tyranny-and-the-end-of-free-software"></span>
    <a href="#tyranny-and-the-end-of-free-software" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The worst possible case for a free project starts like this. A developer builds a piece of software to solve a problem and opens the code. For twenty years, hundreds of people use it and contribute.</p>
<p>Then a cause comes along, any cause, and someone appoints themselves its representative. Through social pressure and propaganda, the maintainers become pariahs. The trade press amplifies it, because controversy attracts readers. The code stops being the subject: what counts now is each contributor&rsquo;s personal opinions, appearance, and past.</p>
<p>From that point on, participating in the project becomes a risk. Contributing pays no value anymore; all it pays is exposure. One by one, the people who actually wrote code walk away, and the project withers. It&rsquo;s a perverse way of seizing a property and destroying its value without formally confiscating anything.</p>
<p>Ayn Rand dramatized exactly this mechanism in Howard Roark&rsquo;s trial in &ldquo;The Fountainhead&rdquo;, and <a href="/en/2011/02/04/off-topic-the-fountainhead-defesa-de-howard-roark">I wrote about it in 2011</a>:</p>
<blockquote>
  <p>&ldquo;I came here to say that I do not recognize anyone&rsquo;s right to one minute of my life. Nor to any part of my energy. Nor to any achievement of mine. No matter who makes the claim!&rdquo;</p>

</blockquote>
<p>That&rsquo;s the warning. A political layer on top of a free project destroys the market that sustained it.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>None of this condemns anyone who contributes out of social motivation. Whoever trades their code for the feeling of helping is making a voluntary exchange like any other, and outside software that has a name: donation and volunteer work. The trouble starts when someone decides that other people&rsquo;s property must serve the cause they picked.</p>
<p>Solving the world&rsquo;s problems is much harder than arguing about them. Bill Gates delivered that message in 2000, pushing back on the hype that PCs would end poverty:</p>
<blockquote>
  <p>&ldquo;Fine, go to those Bangalore Infosys centers, but just go and try those guys three miles outside, and look at the people who are living without a toilet, without running water&hellip; The world is not flat and PCs are not, in the hierarchy of human needs, in the first five rungs.&rdquo;</p>

</blockquote>
<p>Programmers, from any social class, have internet and resources to spare, enough to spend the day on social media debating how to save the world. The people actually working on those problems are outside that circuit, <a href="https://en.wikipedia.org/wiki/Computer_technology_for_developing_areas"target="_blank" rel="noopener">doing instead of talking</a>.</p>
<p>I&rsquo;ll close with a real story someone told me, names removed:</p>
<blockquote>
  <p>A: Man, nobody gives my [minority] a chance.</p>
<p>B: Why don&rsquo;t you help me fix these issues in this open source project? Then you can give talks about it.</p>
<p>(A vanishes. B waits, gets tired, and calls C, who fixes the issues and gets the speaking slot.)</p>
<p>A: See, B? You&rsquo;re one of the oppressors who won&rsquo;t give people like me a shot, and you&rsquo;d rather hand the opportunity to C.</p>

</blockquote>
<p>And a personal note to wrap up. People label me an &ldquo;Ayn Rand follower&rdquo;, and they&rsquo;re wrong: Rand merely put in writing, before me, what I already thought and practiced. Same goes for Bastiat, Friedman, Hayek, or Menger. They&rsquo;re references, and references are not owners. Judging an idea by its author instead of judging the argument on its merits is the definition of <a href="https://en.wikipedia.org/wiki/Ad_hominem"target="_blank" rel="noopener">ad hominem</a>, and I don&rsquo;t respond well to fallacies.</p>
]]></content:encoded><category>open-source</category><category>economics</category><category>philosophy</category><category>off-topic</category></item><item><title>[Off-Topic] Someone Important Left the Community! Now What??</title><link>https://akitaonrails.github.io/en/2014/07/06/off-topic-alguem-importante-deixou-a-comunidade-e-agora/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2014/07/06/off-topic-alguem-importante-deixou-a-comunidade-e-agora/</guid><pubDate>Sun, 06 Jul 2014 20:38:00 -0300</pubDate><description>&lt;p&gt;This week a well-known Node.js community developer announced he was jumping ship. It was &lt;a href="https://medium.com/code-adventures/farewell-node-js-4ba9e7f3e52b"target="_blank" rel="noopener"&gt;TJ Holowaychuk&lt;/a&gt;, one of the most prolific contributors to that community. As you&amp;rsquo;d expect, the news kicked up controversy, arguments, and people freaking out.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re an experienced programmer, you don&amp;rsquo;t need me to tell you this. But if the recent news rattled you, maybe what I have to say will give you some perspective.&lt;/p&gt;
&lt;p&gt;First, I want to share a few other articles I read over the last few days:&lt;/p&gt;</description><content:encoded><![CDATA[<p>This week a well-known Node.js community developer announced he was jumping ship. It was <a href="https://medium.com/code-adventures/farewell-node-js-4ba9e7f3e52b"target="_blank" rel="noopener">TJ Holowaychuk</a>, one of the most prolific contributors to that community. As you&rsquo;d expect, the news kicked up controversy, arguments, and people freaking out.</p>
<p>If you&rsquo;re an experienced programmer, you don&rsquo;t need me to tell you this. But if the recent news rattled you, maybe what I have to say will give you some perspective.</p>
<p>First, I want to share a few other articles I read over the last few days:</p>
<ul>
<li>
<p><a href="http://www.mikeperham.com/2014/07/02/my-next-chapter/"target="_blank" rel="noopener">My Next Chapter</a>: the statement by <a href="http://web.archive.org/web/20150321122529/https://plus.google.com/118252393888359805350"target="_blank" rel="noopener">Mike Perham</a>, one of the best-known Rubyists of this generation and creator of the ubiquitous, excellent Sidekiq. He&rsquo;s not abandoning the project; he&rsquo;s building a new product, and that product doesn&rsquo;t involve Ruby.</p>
</li>
<li>
<p><a href="http://www.ianbicking.org/blog/2014/02/saying-goodbye-to-python.html"target="_blank" rel="noopener">Saying Goodbye To Python</a>: here it was the Pythonista Ian Bicking, announcing he was trading Python for JavaScript, riding the current wave. Worth understanding that today&rsquo;s JavaScript bubble doesn&rsquo;t &ldquo;require&rdquo; you to &ldquo;leave&rdquo; anything for it. You can quietly stay a Pythonista and use JavaScript at the same time, no conflict.</p>
</li>
<li>
<p><a href="http://blog.jonathanoliver.com/why-i-left-dot-net/"target="_blank" rel="noopener">Why I Left the .Net Framework</a>: a developer named Jonathan Oliver also decided to lay out why he&rsquo;s leaving his day-to-day technology, weighing the pros and cons of the Microsoft stack. No troll here; it&rsquo;s actually a pretty interesting read.</p>
</li>
<li>
<p><a href="https://medium.com/tales-from-6w/java-again-5de2c1aa6857"target="_blank" rel="noopener">Java Again</a>: anyone from the first generations of the Java community remembers James Duncan Davidson, creator of nothing less than the first Tomcat and Ant. He left Java, spent a while in the Ruby community, and threw himself into photography (go look for photos of the RubyConfs from eight years ago and you&rsquo;ll see the official ones are all his). Now he&rsquo;s announced he&rsquo;s going back to Java.</p>
</li>
<li>
<p><a href="http://yager.io/programming/go.html"target="_blank" rel="noopener">Why Go Is Not Good</a>: as the title says, it&rsquo;s a critique arguing that a freshly launched language should have been thought through better to cover cases other languages already handle.</p>
</li>
<li>
<p><a href="http://jaredly.github.io/2014/03/22/rust-vs-go/"target="_blank" rel="noopener">Rust vs Go</a>: again with a whiff of sour grapes. Rust really does look like a technically superior language to Go in design and features, and the piece shows the frustration of watching Go stay more popular anyway.</p>
</li>
<li>
<p><a href="http://outspeaking.com/words-of-technology/why-perl-didnt-win.html"target="_blank" rel="noopener">Why Perl Didn&rsquo;t Win</a>: mandatory reading on the fortunes of one of the most popular languages from the late 80s to the late 90s, which fell into obscurity and disuse. Even Swift, released by Apple weeks ago, already has more active users than Perl 6. One of the takeaways: anything new has to aim at the problems of the future, not the ones from the past.</p>
</li>
</ul>
<p>Anyone from the first generations of the Ruby and Rails communities will remember the &ldquo;traumas&rdquo; we went through:</p>
<ul>
<li>
<p><a href="http://web.archive.org/web/20140709000638/http://www.akitaonrails.com/2008/1/1/zed-shaw-vs-rails"target="_blank" rel="noopener">Zed is Not Dead</a>: from 2008, when one of our most prolific developers, Zed Shaw, creator of Mongrel and one of the first to take on the challenge of measuring and optimizing Ruby&rsquo;s performance, announced he was leaving the community and moving to Python.</p>
</li>
<li>
<p><a href="http://web.archive.org/web/20140709094857/http://www.akitaonrails.com/2008/12/23/bomba-merb-e-rails-se-fundem"target="_blank" rel="noopener">Bomb: Merb and Rails Merge!</a>: also from 2008, when the Merb team was on a collision course with Rails Core. The solution, happy for many and unhappy for a stubborn few, was to fold Merb into Rails 3, and it left dead and wounded behind. In retrospect, it&rsquo;s worth reading <a href="http://web.archive.org/web/20140626092759/http://merbist.com/2012/02/29/learning-from-rails-failures/"target="_blank" rel="noopener">&ldquo;Learning from Rails&rsquo; failures&rdquo;</a> by Matt Aimonetti (who also moved to Go) and who counts among the wounded of that insurgency, and <a href="http://gilesbowkett.blogspot.fr/2014/06/the-railsmerb-merge-in-retrospect.html"target="_blank" rel="noopener">&ldquo;The Rails/Merb Merge In Retrospect&rdquo;</a> by Giles Bowkett (still a Rubyist), who breaks down the results with a very critical eye.</p>
</li>
<li>
<p><a href="http://www.akitaonrails.com/2011/04/16/twitter-muda-de-ruby-para-java-ruby-e-3x-mais-lento-que-java"target="_blank" rel="noopener">Twitter switches from Ruby to Java</a>: from 2011, when Twitter announced it was replacing the messaging-infrastructure parts written in Ruby with a proprietary solution in Scala. What the original news said and what people chose to remember are two different things, but the fact is it turned into a good Public Relations headache for us. Thankfully that one&rsquo;s behind us.</p>
</li>
</ul>
<p>And these are just the links I&rsquo;ve read and can recall off the top of my head. There are dozens more.</p>
<p>Anyone still young or inexperienced in software communities, especially newcomers to Node.js, must be asking themselves: <em>&ldquo;Now what? If someone important like TJ says he&rsquo;s leaving, shouldn&rsquo;t I leave too?&rdquo;</em> Do your homework and you&rsquo;ll see this isn&rsquo;t the first time. In 2012 the creator of Node.js, <a href="http://venturebeat.com/2012/01/30/dahl-out-mike-drop/"target="_blank" rel="noopener">Ryan Dahl announced</a> he&rsquo;d keep an eye on his project but would step out of the day-to-day coding. <em>&ldquo;Man, the world is ending!&rdquo;</em></p>
<h2>This Isn&rsquo;t Bad News. This Is an Excellent Opportunity! (Seriously!)<span class="hx:absolute hx:-mt-20" id="this-isnt-bad-news-this-is-an-excellent-opportunity-seriously"></span>
    <a href="#this-isnt-bad-news-this-is-an-excellent-opportunity-seriously" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In 2006, right as I was starting my run as an activist in the Ruby and Rails world, I already knew what was coming. We were the newcomers, immature, with unfinished technology and a pile of expectations, so naturally the road would be as hard as it gets. That&rsquo;s why I wrote the article <a href="http://www.akitaonrails.com/en/2006/09/27/evolu%c3%a7%c3%a3o-pela-concorr%c3%aancia"target="_blank" rel="noopener">Evolution through Competition</a>.</p>
<p>A lot of people imagine the best of all worlds is the one where nobody questions what you&rsquo;re doing, everyone leaves you alone, and they take your promises on faith, promises you fully intend to keep, someday. (<em>yeah, right&hellip;</em>)</p>
<p>I disagree. Any promise or expectation worth having has to be questioned, pushed, scrutinized. If it&rsquo;s so fragile it can&rsquo;t take criticism, direct and indirect attacks, and sabotage, then the promise was weak to begin with and didn&rsquo;t deserve to move forward. The sooner it falls, the better, because that&rsquo;s less time wasted.</p>
<p>That&rsquo;s why I always welcome the attacks: I expect to be ready to hit back twice as hard or die trying. And I&rsquo;d expect nothing less from the Rails community. Everyone still believes constraints are bad, but I&rsquo;ve <a href="http://startupi.com.br/2013/restricoes-sao-libertadoras-menos-e-mais/"target="_blank" rel="noopener">said before</a> that constraints matter, because they&rsquo;re the only place <strong>innovation</strong> comes from.</p>
<p>Anyone who has to reach for the old trick of trashing others, the classic <em>&ldquo;I don&rsquo;t feel like getting better, so I&rsquo;ll drag the other guy down to look bigger&rdquo;</em> (I wrote about this back in 2007 too, <a href="http://web.archive.org/web/20140709023445/http://www.akitaonrails.com/2007/10/23/para-eu-ganhar-o-outro-precisa-perder"target="_blank" rel="noopener">&ldquo;For me to win, the other has to lose&hellip;&rdquo;</a>), is declaring himself weak all on his own. Stop and think back to articles, talks, and interviews where you heard someone you admire trashing another community. <em>&ldquo;Ah, Ruby, that girly thing. Because we men use JavaScript.&rdquo;</em> It makes me laugh and feel a little sorry, because to me it&rsquo;s clear that person will always be weak.</p>
<p>All the statements above, and others like them (&ldquo;I&rsquo;m leaving Node&rdquo;, &ldquo;I&rsquo;m leaving .NET&rdquo;, &ldquo;I&rsquo;m leaving Ruby&rdquo;, &ldquo;I&rsquo;m leaving X&rdquo;), I honestly believe came with no bad intent or bad faith, at least not consciously. But I have a theory. Everyone who makes statements like that wants validation from their peers, or worse, wants their peers to follow them, which is also validation of their own position. <em>&ldquo;I don&rsquo;t like my old toy anymore, but I don&rsquo;t want anyone else playing with it either.&rdquo;</em> It&rsquo;s a pretty childish stance.</p>
<p>Take the Ruby community as an example. Plenty of names sort of &ldquo;left&rdquo; their main activities without slamming the door or acting childish about it. Chad Fowler is in Germany running Wunderlist, focused on mobile and back-end development, and we don&rsquo;t hear him talk Ruby anymore. Ilya Grigorik had his startup bought by Google and eventually dropped off too. Matt Aimonetti, after the Merb vs Rails episode, quietly stepped back and now works with Go.</p>
<p>Ryan Bates, one of the most beloved in the community for his tireless years of work on RailsCasts, stopped publishing months ago and said nothing about it. David Chelimsky, maintainer of RSpec, handed off the baton and stepped away without any fuss. José Valim, one of the key people behind Rails 3, is over in Elixir and Erlang land now and rarely says a word about Ruby.</p>
<h2>&ldquo;O.M.G! You mean it&rsquo;s all over!? It went up in flames!?&rdquo;<span class="hx:absolute hx:-mt-20" id="omg-you-mean-its-all-over-it-went-up-in-flames"></span>
    <a href="#omg-you-mean-its-all-over-it-went-up-in-flames" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No. In the meantime, hundreds of new Rubyists showed up and carried the work forward. The most immediate example is Carlos Antonio and Rafael França, who sort of picked up José Valim&rsquo;s mantle in Rails Core. Evan Phoenix picked up Chad Fowler&rsquo;s mantle at Ruby Central. Avdi Grimm sort of picked up Ryan Bates&rsquo; mantle with his excellent <a href="http://www.rubytapas.com"target="_blank" rel="noopener">RubyTapas</a>, and on it goes.</p>
<p>A community is made of individuals, and each individual performs best when acting to maximize their own benefit. The side effect is that they end up naturally influencing and pulling others up alongside them. It&rsquo;s always voluntary exchange for <strong>mutual</strong> benefit. Nobody acts with zero benefit to themselves; some believe they do, and those are exactly the ones who hit &ldquo;burnout&rdquo; fastest, because the question quickly becomes:</p>
<blockquote>"Why do I wear myself out collaborating in this community, stress myself out, and even so not everyone appreciates what I do? I do it all for them!"</blockquote>
<p>That&rsquo;s the wrong question, and the wrong question leads to the wrong answer. Some start to believe others owe them something, since they poured so much of their free time (especially in the open source world) into &ldquo;helping others&rdquo;. And &ldquo;the others&rdquo; figure they owe nothing, since nobody asked for that effort in the first place. In practice, &ldquo;the others&rdquo; are right.</p>
<p>If you take part in a community, you do it for yourself. Maybe because you understand that helping others is part of your own reward. Maybe because it gives you peace of mind or a clear conscience. Or because you&rsquo;re a good strategist and know certain contributions will open doors for you down the line. The reason doesn&rsquo;t matter, as long as there&rsquo;s a reward you don&rsquo;t force others to hand over. Demanding respect, demanding manners, demanding compassion, none of it makes sense without a counterpart. Nobody asked you to do what you&rsquo;re doing; if you are, understand it&rsquo;s for yourself. That&rsquo;s the definition of <strong>voluntary</strong> work.</p>
<p>And to be crystal clear: voluntary work means work without <strong>financial pay</strong>, and not work without benefit or purely altruistic. If your work is paid, that&rsquo;s a different conversation, and the best advice there comes from Don Draper:</p>
<style>.embed-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; height: auto; } .embed-container iframe, .embed-container object, .embed-container embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }</style><div class='embed-container'>

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/EnPHp4vwxGM"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>
</div>
<p>Back to the topic, I imagine the names I mentioned above, the ones who stepped back partially or quietly, get this. They went looking for personal satisfaction elsewhere. They owe nothing to anyone, and nobody owes anything to them.</p>
<p>The ones who leave with bombastic declarations are, consciously or not, throwing it in everyone&rsquo;s face: <em>&ldquo;you didn&rsquo;t value me, now you&rsquo;ve lost your chance, and I know you&rsquo;ll miss me!&rdquo;</em> It isn&rsquo;t written that way, but that&rsquo;s what it adds up to. Otherwise, why throw it into the fan and turn it into a public controversy? Any written argument is only part of the reason, never &ldquo;the&rdquo; reason.</p>
<h2>You, the Individual<span class="hx:absolute hx:-mt-20" id="you-the-individual"></span>
    <a href="#you-the-individual" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The flip side is whoever follows, admires, and idolizes one of these people who walked away from where you are. Depending on how deep the admiration runs, you feel the floor drop out, stunned, not knowing which way to run. One of two things happens: you either go hunting for another idol and start the classic <em>&ldquo;he wasn&rsquo;t even that good&rdquo;</em>, or you sink into depression and the panic of <em>&ldquo;I don&rsquo;t know what happens now&rdquo;</em>.</p>
<blockquote>My advice: "don't have idols, have references."</blockquote>
<p>Stop thinking you owe others something and, by extension, stop dumping on others the job of helping still more people. That&rsquo;s what&rsquo;s going on: you don&rsquo;t understand your <strong>purpose</strong> and figure others should do what you yourself won&rsquo;t. Worse, you let others decide which road you take. If you&rsquo;re that insecure, stop for a second and think about what you &ldquo;are&rdquo; before anything else.</p>
<p>Your only purpose in life is to take care of yourself and produce, without getting in anyone else&rsquo;s way. When you do that, the natural effect is that spontaneous collaborations spring up, communities evolve, and everyone comes out ahead. A community where everyone makes demands on everyone grows without any purpose.</p>
<p>On technology, opinions, proposals, and promises, remember this too: you <strong>want</strong> to be under constant &ldquo;attack&rdquo; and constraint. Nothing is worse than being ignored. I wrote another article, a translation from someone far wiser than me, Kathy Sierra, called <a href="http://www.akitaonrails.com/en/2006/10/19/kathy-sierra-dilbert-e-a-zona-de-mediocridade"target="_blank" rel="noopener">Dilbert and the Zone of Mediocrity</a>, where I quote:</p>
<blockquote>
How brave are you? How far will you (or your employer) go to avoid the Zone of Mediocrity? Until or unless you're willing to risk passionate hate, you may never feel the love. Scott Adams agrees. In a recent post on the Dilbert blog, he wrote: "If everyone exposed to a product likes it, the product will not succeed... The reason that a product 'everyone likes' will fail is because no one 'loves' it. The only thing that predicts success is passion, even if only 10% of the consumers have it."
</blockquote>
<p>So what if someone left your community? Is it so fragile that one blow, no matter the size of the impact, brings the whole thing down? If you believe your community is only <strong>resistant</strong>, you&rsquo;re right: past a certain point, it collapses. But if it&rsquo;s <strong>resilient</strong>, malleable and adaptive, it survives. That&rsquo;s what guarantees the survival of species, the <a href="http://c2.com/cgi/wiki?SurvivalOfTheFittest"target="_blank" rel="noopener"><strong>Law of the Most Adaptable</strong></a> (not the &ldquo;strongest&rdquo;! Keep the difference between resistant and resilient in mind, you want to be the second one).</p>
<p>Are you adaptable? Or are you just fishing for other people&rsquo;s validation, letting them decide for you? One thing I&rsquo;ll say for sure: if I ever give up what I do, nobody will find out from a written statement. I settled that the day I started.
</content></p>
]]></content:encoded><category>open-source</category><category>philosophy</category><category>management</category><category>off-topic</category></item><item><title>Chatting with Chris Wanstrath (Err the Blog/Github)</title><link>https://akitaonrails.github.io/en/2008/04/21/chatting-with-chris-wanstrath-err-the-blog-github/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2008/04/21/chatting-with-chris-wanstrath-err-the-blog-github/</guid><pubDate>Mon, 21 Apr 2008 19:12:00 -0300</pubDate><description>&lt;p&gt;Chris is a very accessible and easy-going guy, and I just got him out of AIM and started the interview right away. For those of you who never heard of &lt;strong&gt;&amp;lsquo;Chris Wanstrath&amp;rsquo;&lt;/strong&gt; , he is also known for Err the Blog and recently as one of the guys behind the &lt;strong&gt;Github&lt;/strong&gt; phenomenon.&lt;/p&gt;
&lt;p&gt;He answered everything in colorful detail and we speak a lot about his open source projects, performance, scalability and, of course, lots of Git and Github stuff. Hopefully it will make people even more excited about how the Ruby/Rails community is moving things forward all the time.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Chris is a very accessible and easy-going guy, and I just got him out of AIM and started the interview right away. For those of you who never heard of <strong>&lsquo;Chris Wanstrath&rsquo;</strong> , he is also known for Err the Blog and recently as one of the guys behind the <strong>Github</strong> phenomenon.</p>
<p>He answered everything in colorful detail and we speak a lot about his open source projects, performance, scalability and, of course, lots of Git and Github stuff. Hopefully it will make people even more excited about how the Ruby/Rails community is moving things forward all the time.</p>
<p><strong>aos leitores brasileiros:</strong> assim que tiver tempo irei traduzir esta entrevista.</p>
<p><strong>AkitaOnRails:</strong> Ok, so, where are you from?</p>
<p><strong>Chris Wanstrath:</strong> Right now I live in San Francisco but I grew up in Cincinnati, Ohio. I moved to San Francisco in 2005 to work for C|NET where I did PHP for a while on sites like <a href="http://gamespot.com"target="_blank" rel="noopener">gamespot.com</a>, <a href="http://mp3.com"target="_blank" rel="noopener">mp3.com</a>, and <a href="http://tv.com"target="_blank" rel="noopener">tv.com</a></p>
<p>In 2006 I moved over to the <a href="http://chowhound.com"target="_blank" rel="noopener">chowhound.com</a> site within C|NET to work on Rails, which is something I had been doing on the side for a while. While I was there <strong>P.J. Hyett</strong> and myself worked on chowhound.com then built <a href="http://chow.com"target="_blank" rel="noopener">chow.com</a>, which we launched later that year. Then in April of 2007 we both left C|NET to form our consulting company, Err Free.</p>
<p>In December of 2007 we launched <a href="http://famspam.com/"target="_blank" rel="noopener">FamSpam</a>, which is a site for keeping in touch with your family. It&rsquo;s basically a simplified version of Google Groups with emphasis on participating in a thread at least once a week and easily finding photos or other file uploads.</p>
<p>While P.J. and I were working on FamSpam, <strong>Tom Preston-Werner</strong> and I were working on GitHub on the side. We started in October working nights and weekends on it. We basically wanted an easy, pretty, and feature-rich way to throw our Git repos up and share them with people. Then as we got more into it, we realized how things like the dashboard could change the way we deal with open source contributions. After that, all the social features began to fall into place. Github private beta launched in january, and in april we saw the public launch</p>
<p><strong>AkitaOnRails:</strong> Wow, Cool, you are a very busy guy indeed, I want to go on in details within each topic you mentioned but first I knew you worked for C|Net because of your memcached keynotes. I have 2 questions: you were a PHP programmer, what made you switch to Ruby on Rails? And then, working for a high profile network like C|Net exposed you to very demanding public websites. How did you figured out about leveraging memcached with Rails and then your cache_fu plugin?</p>
<p><strong>Chris Wanstrath:</strong> I started doing Rails at the start of 2005 and got my first PHP job in February of 2005. (before that I was doing asp and Perl, which I don&rsquo;t like to talk about). So really, I never considered myself a &ldquo;PHP programmer&rdquo; over a Rails programmer. I really liked websites and I knew I could get paid doing PHP, so that&rsquo;s what I did. In the meantime, I was constantly doing Ruby on the side.</p>
<p>When C|Net started doing Rails, I knew it would be a perfect fit for me. I really liked PHP and loved Gamespot, but it was just silly for me to spend all night playing with Ruby while doing PHP professionally.</p>
<p>In fact, one of the things that got me hired at Gamespot was my pure PHP yaml parser called <a href="http://spyc.sourceforge.net/"target="_blank" rel="noopener">SPYC</a> (simple PHP yaml class). It was inspired (obviously) by _why&rsquo;s syck yaml parser. I wanted an easy, extension-free way to deal with YAML in PHP because I was so spoiled by Ruby.</p>
<p>I think today the CakePHP and Symfony frameworks use it, and do their config stuff in yaml. But even when writing PHP I wanted to be writing Ruby. The main reason I picked up ruby in the first place is because I knew PHP, and I knew Perl, but I wanted something I could use to write both websites and command line scripts. Perl was great for scripts, and PHP was great for sites, but I was just tired of using them both</p>
<p>So while I was learning Python, Rails popped up.</p>
<p>As far as <a href="http://errtheblog.com/posts/57-kickin-ass-w-cachefu"target="_blank" rel="noopener">cache_fu</a> goes, I was very interested in some of the &ldquo;scaling&rdquo; aspects of running a website while working at Gamespot.</p>
<p>While good OOP design and stuff like that can be learned by anyone writing enough code, you can&rsquo;t really learn about scaling unless you&rsquo;re working on a big website. There are just too many tricks and moving parts, and it&rsquo;s too hard to simulate the load in a controlled environment.</p>
<p>So while at Gamespot, like I said, I tried to learn as much as possible about things like MySQL replication, clustering databases, sharding databases, and memcached based on how the smart guys at C|Net had set it all up over the years. They had a lot of machines serving a lot of traffic so it was perfect</p>
<p>At Chowhound, we were re-writing an old static html site in Rails and were worried about the transition from flat files to dynamic database calls and page generation. It had a fair amount of traffic from a group of rabid fans, and we knew the new &ldquo;web 2.0&rdquo; look of the site would not sit well with the old school users, so we at least wanted the site to be performant in order to give them one less thing to complain about. So we basically took a lot of what I had learned at Gamespot, and what information was freely available on the internet in mailing lists and discussions, and tried to do a more Rails friendly way of object caching with memcached.</p>
<p>Ruby is just so good at cleaning up repetition and creating friendly apis. So cache_fu does fragment caching and object caching, because in bigger sites you end up using both for different purposes which is how it was at Gamespot too, basically.</p>
<p><strong>AkitaOnRails:</strong> Nice. And it is not very common for me to find people that have dealt with really big websites. Can you give us a glimpse of what kind of load your Rails apps did have to handle? Some pundits I know complain about the vanilla Rails distribution and recommend lots of tweaks like dumping ActiveRecord altogether and several other hacks. Do you have to hack Rails a lot in order to achieve the scalability you need or do you think most of it is good enough so you can avoid too much tweaking?</p>
<p><strong>Chris Wanstrath:</strong> I wouldn&rsquo;t really consider Chowhound to be a big Rails site anymore. Now that you&rsquo;ve got scribd and twitter and friends for sale and Yellowpages, Chowhound doesn&rsquo;t really make the list.</p>
<p>We ended up doing a lot of premature optimization on that site, and not enough real world optimization. I learned a lot of lessons there that I&rsquo;ve applied to other sites along the way. However, I recently had the chance to work with the friends for sale guys on their Facebook app which gets millions of page views a day and handles an insane amount of db records.</p>
<p>To my knowledge, the only AR hack we did was apply Pratik Naik&rsquo;s partial updates patch. This was because, with so many rows and such large indexes, you want to avoid modifying indexes when you don&rsquo;t need to, so saving only the changed columns/attributes can have a real big performance gain. Luckily, partial updates are now in Rails Core.</p>
<p>In my experience, you spend a lot more time trying to scale SQL before you even need to address AR. And once you get to the AR part, it&rsquo;s usually your application code. Fetching and saving too many records in before/after_save callbacks, full row writes like I was just describing, and generally not being a good SQL citizen. I would only ditch AR completely if I felt like I had no control over the SQL it generated. Which, as anyone knows, is not the case – you have a lot of control over it.</p>
<p>There are times, however, when AR is overkill and you really do need speed. On Github, we need to authenticate you every time you try and pull or push a repository over ssh. Loading an entire Rails environment, or even activerecord, was noticeably slow, so we switched to using sequel in a simple ruby script. Because we don&rsquo;t need AR&rsquo;s massive featureset and nice OOP capabilities for such a simple single row find, this made a lot of sense for us.</p>
<p><strong>AkitaOnRails:</strong> I agree with that, that&rsquo;s what I experienced too with regards to AR. So, and you&rsquo;re also the author of several other famous Rails plugins like will_paginate, Ambition, the original Sexy Migrations. Can you comment briefly about each. Am I forgetting any other plugins? Some of what you did became the &lsquo;de facto&rsquo; standards for Rails development, some people here use these plugins without really knowing you made them all.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/4/21/113964679_23c106ba1b.jpg" alt=""  loading="lazy" /><br>
<em>P.J Hyett at SXSW'06</em></p>
<p><strong>Chris Wanstrath:</strong> <a href="http://errtheblog.com"target="_blank" rel="noopener">Err the blog</a> is actually two people, P.J. Hyett and myself. I did not write <a href="http://errtheblog.com/posts/56-im-paginating-again"target="_blank" rel="noopener">will_paginate</a> – P.J. wrote the original version then Mislav Marohnić re-wrote it. Mislav is now the maintainer. But I still get all the credit, which is fine by me.</p>
<p>As far as the other plugins go, there&rsquo;s mofo, ambition, sexy migrations, cache_fu, acts_as_textiled, fixture_scenarios_builder, and gibberish.</p>
<p><a href="http://errtheblog.com/posts/35-me-and-uformats"target="_blank" rel="noopener">Mofo</a> is a microformat parser based on Hpricot. It&rsquo;s up on Github and unfortunately doesn&rsquo;t get enough love from me these days, but as far as I know it&rsquo;s still the gold standard for microformat parsing in Ruby.</p>
<p>It was the first gem that I released which doubled as a Rails plugin, which is how I think most plugins should be distributed in the future. Gems already have a solid distribution system and versioning scheme, and if Github becomes a gem source then there&rsquo;s almost no reason not to release plugins as gems</p>
<p><a href="http://errtheblog.com/posts/51-sexy-migrations"target="_blank" rel="noopener">Sexy migrations</a> were inspired by Hobo. Unfortunately their version was hobo-specific, so I wrote a plugin-friendly version. DHH later wrote his own version and rolled it into core, making a grand total of 3 distinct sexy migration implementations.</p>
<p><a href="http://errtheblog.com/posts/55-ya-talkin-gibberish"target="_blank" rel="noopener">Gibberish</a> is a pretty fun localization plugin I wrote <em>pro bono</em> for a client, just because I felt like the APIs of all the existing localization plugins were so difficult to work with. Hopefully, with the help of anyone interested, we can begin localizing Github in the near future.</p>
<p><a href="http://errtheblog.com/posts/64-even-more-ambitious"target="_blank" rel="noopener">Ambition</a> was inspired by dabbling in Erlang. I read a blog post explaining that <a href="http://www.infoq.com/news/2007/08/mnesia"target="_blank" rel="noopener">mnesia&rsquo;s</a> query syntax, which is all list comprehension (basically Ruby&rsquo;s version of the Enumerable module), was made possible by the ability to walk the parse tree and build an mnesia query that way.</p>
<p>So I started playing with the parse_tree gem to see if I could do the same for Ruby. It&rsquo;s now, of course, a full fledged framework for generating arbitrary queries for any RubyGem based on Enumerable. For simple queries, I really like treating tables as arrays, it feels very natural.</p>
<p><a href="http://errtheblog.com/posts/12-actsastextiled"target="_blank" rel="noopener">Acts_as_textiled</a> was the first Rails plugin I released. It&rsquo;s a testament to Rails that the plugin still works on edge today. The only other notable thing that Err started is the &ldquo;vendor everything&rdquo; term, which is now a part of Rails through <a href="http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies"target="_blank" rel="noopener">config.gems</a>.</p>
<p>That, and the <a href="http://errtheblog.com/posts/21-cheat"target="_blank" rel="noopener">Cheat</a> gem (and site).</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/4/21/322610984_f5d9e82bda.jpg" alt=""  loading="lazy" /><br>
<em>Tom Preston-Werner</em></p>
<p><strong>AkitaOnRails:</strong> (Of course, pardon me P.J.!) And this raises another curiosity of mine: where did the name &ldquo;Err&rdquo; come from? It is both for <a href="http://errtheblog.com/"target="_blank" rel="noopener">Err the Blog</a> and <a href="http://errfree.com/"target="_blank" rel="noopener">Err Free</a> which is your company. And you mentioned P.J. and Tom. And you&rsquo;re all full time Railers, right? How did you team up with them and decide to start your own company? Many times people ask me about entrepreneurship and you&rsquo;re another good example.</p>
<p><strong>Chris Wanstrath:</strong> &ldquo;err&rdquo; is kind of a play on &ldquo;Typo,&rdquo; which was the popular Rails blogging engine when we started our blog, so it may be kind of confusing, but I actually am cofounder of two distinct companies.</p>
<p>There is <strong>Err Free</strong> and <strong>Logical Awesome</strong>. Err Free is Ruby &amp; Rails consulting and training. P.J. and I own the company, and we use it to do client work, speaking gigs, corporate training, that sort of thing. It also owns and operates FamSpam, which we use with our own families.</p>
<p>Logical Awesome, however, was founded by me and Tom. This is because I was developing FamSpam with P.J. and GitHub with Tom at the same time, separately. Today, however, P.J. is a part of Logical Awesome and is one of the GitHub developers.</p>
<p>Tom works at <strong>Powerset</strong> and doesn&rsquo;t actually do much Rails for GitHub, he mainly does flash, haxe, C, css, design, and ruby. And because he&rsquo;s the author of <a href="http://god.rubyforge.org/"target="_blank" rel="noopener">God</a>, I make him write all the config files, too. As far as deciding to start a company, I am someone that needs to be involved in whatever I&rsquo;m involved with on every level. At C|Net, there is only so much input you can have on a website that employs 30 people especially when there are dedicated product and &ldquo;vision&rdquo; people, whereas with Github, it&rsquo;s just me Tom and P.J.</p>
<p>If the site is slow, confusing, sucks, or doesn&rsquo;t improve your workflow, I can take responsibility for that. But if it&rsquo;s fast, simple, awesome, and life changing, I get to take responsibility for that, too. Which is very rewarding.</p>
<p>It also means, when you&rsquo;re cofounder of a mostly technical company, the discussions are a lot more logical. I saw decisions made at C|Net that directly contradicted a/b statistics we had gathered. At Logical Awesome, that would never happen. It is neither logical nor awesome. Basically: I wanted to find the ideal company so I found good people and started it.</p>
<p><strong>AkitaOnRails:</strong> Ok, so we come to the main dish of the day: <a href="http://github.com"target="_blank" rel="noopener">Github</a>! I can&rsquo;t think of a better example of an innovative product that leverages so well the power of Git. I am very curious to understand how did you come up with this idea? At the same time, lots of people still can&rsquo;t understand why Railers as a whole started using Git so massively all of a sudden. Mercurial, Bazaar guys are very uncomfortable. What do you think Git has that attracted Railers in flocks like that? Or at least what do you think Git has that no other have? I started evangelizing Git here in Brazil last year after listening Randall Schwartz, and recently someone asked me what would be my pick for a Rails killer-app and Github popped out of my mind, right away. So you do have good mind share as well.</p>
<p><a href="http://github.com"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/4/21/Picture_1.png" alt=""  loading="lazy" /></a></p>
<p><strong>Chris Wanstrath:</strong> Github is super exciting to me because it&rsquo;s really a website just for me. Tom and I are pretty similar in that we both have a fair amount of open source projects, all of which get used and patched by people we&rsquo;ve never met.</p>
<p>Handling this the old fashion way was fine until me and P.J. started working on FamSpam… as my free time decreased, so did my ability to maintain my open source projects. And really, that&rsquo;s a definite workflow problem. Sometimes when you can&rsquo;t find enough time to do something, you just need to make the something take less time.</p>
<p>Github was literally written for chronic, god, ambition, will_paginate, and the rest of our projects. We wanted to make it dead simple for people to contribute, and really, it&rsquo;s just not possible without Git.</p>
<p>I had started using Git right after viewing the <a href="http://www.youtube.com/watch?v=4XpnKHJAok8"target="_blank" rel="noopener">Linus tech talk</a> in May 2007, which is really good at explaining Git from a very high conceptual level. So when this time problem came up, I had already been using Git for a few months and Tom had serendipitously been trying to solve the same problem.</p>
<p>We talked after a local San Francisco Ruby meetup, at a bar of course (where all great ideas and partnerships begin), and decided to work on the problem together. I&rsquo;d been playing with an err-specific Gitweb, but Github is obviously much more ambitious in its scope.</p>
<p>As far as the adoption of Git, I have no idea what single thing tipped it. When we began working on the app in October, we were worried about ./script/plugin and tarballs and windows and svn mirroring. we weren&rsquo;t even sure we could build a business around Git, because subversion was still so utterly dominant.</p>
<p>As we all know, however, Git tipped at the start of 2008 and everyone somehow found the time to try it out. It maybe takes, like, two seconds to realize how much faster it is, and then a few more seconds after that to realize how much more awesome it is. So it&rsquo;s not much of a surprise that it is grabbing converts.</p>
<p>As for the Rails community, it&rsquo;s definitely because of the projects. When Merb, Rubinius, and Ruby on Rails all switch to Git, you have no choice. This is where the community is headed. As for other languages, we have a large number of non-ruby projects on Github. PHP, Java, Javascript, Lisp, Python — there are a handful of Django forks, for instance, the <a href="http://www.iolanguage.com/"target="_blank" rel="noopener">io</a> and <a href="http://programming.nu/"target="_blank" rel="noopener">nu</a> programming languages are also hosted on Github.</p>
<p>So really what it comes down to is early adopters, I think. Nu is a lisp written on Objective-C, very new and very cutting edge. The people using it right now are people who realize how powerful and awesome it is to run such a dynamic language on such a mature and stable platform. And naturally, the forward thinkers behind nu know that Git (and distributed source control) is an equally powerful, equally cutting edge concept.</p>
<p>With Prototype and Scripatculous moved over, and rumors of other Javascript frameworks switching, it&rsquo;s only a matter of time before Git becomes even more widespread.</p>
<p>I think the Railers just like to blog a lot.</p>
<p>As far as other solutions go, it&rsquo;s Rails vs Django all over again. If you use Mercurial, that&rsquo;s fine. The two are so similar (yes, <a href="http://kylecordes.com/2008/03/22/git-windows-works/"target="_blank" rel="noopener">Git does work great on Windows</a>) that as long as people move to distributed source control, it&rsquo;s still a win.</p>
<p>Oh, but wait, Mercurial doesn&rsquo;t have Github :-)</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/4/21/Picture_3.png" alt=""  loading="lazy" /></p>
<p><strong>AkitaOnRails:</strong> There you go :-) And I wonder what were the challenges of putting something as Github together. It is not a simple Rails web app, with very fast, pure Ruby code. You&rsquo;re probably dealing with thousands of system calls to Git command liners, several background jobs, maintenance, security. What do you think were the biggest challenges while assembling Github before recently releasing it to the public?</p>
<p><strong>Chris Wanstrath:</strong> Well you pretty much nailed it right there… scaling Rails is the easy part. scaling sshd, Git, Git-daemon, and our background jobs is the hard part.</p>
<p>We call Git directly many times per page, we need to process jobs that get entered from many different places (create a repo on the website, push a repo through ssh), we need to be secure (ssl and ssh for all private repos at all times), we need to make sure it all runs fast (memcached for both Git calls and the db), we need to make sure you&rsquo;re <em>&ldquo;in the loop&rdquo;</em> with a news feed aggregating information from all different sources within our system (almost 1m rows in the feed table when we launched).</p>
<p>So it definitely has not been easy. Not to mention that ssl is essentially the &ldquo;slow flag&rdquo; for http, so we need to make sure we&rsquo;re going fast because things like your dashboard already have a speed handicap. As an example, sshd stores its keys in an authorized_keys file. Well, we weren&rsquo;t even done with our beta yet and the keys file was over 4 megs of just plain text. So we had one of the C gurus at Engine Yard patch sshd for us to do mySQL based lookups, giving us faster searches and no pricey appending / writing of a massive file</p>
<p>Matthew Palmer is the said guru, and we plan to make that code open source in the near future.</p>
<p>We&rsquo;ve also got post-receive (when you &ldquo;Git push&rdquo;) hooks running that we host and deliver – so if you push, we&rsquo;ll POST to an arbitrary url for you with json of the commits. But you can also give us some info and we&rsquo;ll post to campfire, irc, twitter, or lighthouse for you with custom payloads.</p>
<p>Since we have flash, flash with haxe, Python, c, ruby, bash scripts, lots of Javascript, and some forthcoming erlang under the hood, it&rsquo;s definitely an interesting mix.</p>
<p>We are fortunate to be hosted on <strong>Engine Yard</strong> , though. If we didn&rsquo;t have them we&rsquo;d be screwed. Their awesome cluster setup with GFS means we can host our potentially 100s of gigs of repositories on a shared, raid&rsquo;d drive with redundancy and backups. If we were running Github on a barebones VPS, I dont even know how we&rsquo;d share access to those repos. It wouldn&rsquo;t be fun.</p>
<p>They also have a lot of experts available 24/7, which is great because I have a tendency to forget to sleep and work until 7am. A lot of the pain of running a heavily unix-dependent site is taken away by those guys.</p>
<p><a href="http://www.flickr.com/photos/ozmm/487496000/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2008/4/21/Picture_5.png" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails:</strong> Interesting, Erlang? I&rsquo;d like to know what you are up to with it. Going back, I think I saw a Rails trunk Git clone at Github way before DHH announced it a few days ago. I think it was Michael Koziarski who first did it, without much fuzz. Were you planning this together with the 37signals guys, or the switch of the Rails Core to Github was something that happened naturally? And do you have any kind of partnership with the Lighthouse guys as well, because you already have some hooks to manage Lighthouse tickets through Github commit messages, right?</p>
<p><strong>Chris Wanstrath:</strong> The Erlang stuff will be very cool, I promise. We&rsquo;ll make a big fuss about it when it&rsquo;s ready. As far as the Rails thing goes, koz did indeed have a mirror of his Git-svn repo at Github during the beta. It was unofficial. Then in february he wrote a <a href="http://www.koziarski.net/archives/2008/2/23/on-Git"target="_blank" rel="noopener">post explaining</a> that the core was thinking about moving to Git.</p>
<p>When I saw the post I emailed him and we talked a bit about what it would take to move Rails to Github, which was obviously something I love on a huge number of levels. He said he would get back to me, and then a few weeks later the Core team contacted us and wanted to discuss the move. The rest is history.</p>
<p>I really respect the work the <a href="http://www.lighthouseapp.com/"target="_blank" rel="noopener">Lighthouse</a> team does. The bug tracker is great, and the new redesign is even better, but we don&rsquo;t have any official partnership with them. We wrote the post-receive lighthouse hook because we wanted it, Rails wanted it, and a huge number of our users wanted it.</p>
<p><strong>AkitaOnRails:</strong> Many others started moving to Github during the Beta. I think Merb was more obvious because of Ezra&rsquo;s being involved in Engine Yard. Dr. Nic started using it for the Textmate bundles. Can you point to any other high profile Rails related projects hosted at Github right now?</p>
<p><strong>Chris Wanstrath:</strong> Merb was actually the reason Github went into beta. We launched the beta so they could start using the site for their 0.9 rewrite of merb-core. As far as popular projects, the best thing to do is check <a href="http://Github.com/popular/watched"target="_blank" rel="noopener">http://Github.com/popular/watched</a> and <a href="http://Github.com/popular/forked"target="_blank" rel="noopener">http://Github.com/popular/forked</a>. Datamapper, Rspec, and Mephisto are some of the popular ones.</p>
<p><strong>AkitaOnRails:</strong> Are you using vanilla Git code, or did you customize it in any way to better fit your environment? Have you ever talked to Junio Hamano or any other Git core maintainer? With Github probably eating up a lot of your time, how is Chow and FamSpam going right now? How are you managing all those products all at once?</p>
<p><strong>Chris Wanstrath:</strong> We&rsquo;ve patched Git-daemon to record statistics, which we&rsquo;ll soon be surfacing on the website soon in the form of better, more granular activity. You&rsquo;ll be able to see how many times your project was cloned, popular projects in the last 24 hours, all time most cloned projects, that sort of thing.</p>
<p>We&rsquo;ve emailed the core Git guys about the site, just to say thanks for writing Git and to let them know about Github, but haven&rsquo;t really had an occasion to chat with them about anything in particular. If I ever run into any of them, I&rsquo;ll definitely be buying them a few drinks, though.</p>
<p>I don&rsquo;t actually work at Chow anymore. My last day at C|NET was almost exactly one year ago, so my Ruby time is spent on FamSpam, Github, open source, and doing occasional client work.</p>
<p>FamSpam is going well. Now that Github is launched, there are a handful of features we want to get in and all. Luckily, however, the site is very polished and has been running smoothly without the need for much intervention. What we&rsquo;d really love to do, because it&rsquo;s really just a great Rails-based mailing list, is try out some different concepts.</p>
<p>Maybe one for open source, or a version for little league teams – anyone who needs to keep in touch and have their email workflow and document sharing streamlined. For right now, however, I try to spend as much time as possible on Github. There are so many places we want to take it.</p>
<p><strong>AkitaOnRails:</strong> I probably more than exceeded my interview time (sorry about that), but this conversation is super-interesting. One project I just remembered is Sake. To me Sake is very neat because many people complain about &ldquo;how difficult and complex&rdquo; the Git command line is, and Sake-like solutions make the workflow a lot easier. For instance, my entire Git workflow for Rails projects is only 4 small sake tasks like Git:update and Git:push. If I am not mistaken someone at Err did Sake, right? Are you still evolving it?</p>
<p><strong>Chris Wanstrath:</strong> Yeah, I wrote <a href="http://errtheblog.com/posts/60-sake-bomb"target="_blank" rel="noopener">Sake</a>. It&rsquo;s not a Rails plugin but it was written to help in Rails development. The &ldquo;Git tasks&rdquo; for Sake are becoming quite popular, as Git really just facilitates a better workflow. If you want to implement it, or different branches of that workflow, you can pretty easily just wrap up a few commands into a rake task or bash script.</p>
<p>And while bash scripts are great, sake tasks are portable. A lot of sake was inspired, very loosely, on Git – you can pull in sake tasks from any text file, whether it&rsquo;s on the web or local, and sake comes with its own daemon for serving your tasks.</p>
<p>So you could share tasks over wifi, or something, the same way you could share Git repositories over an adhoc network. Sake is up on Github, so feel free to add features you feel should exist.</p>
<p><strong>AkitaOnRails:</strong> Another thing I would like to hear your opinion about. I recently made a presentation on Rails Deployment strategies for beginners. The most common simple architecture revolves around Apache/Nginx/Litespeed + Mongrel/Evented Mongrel/Thin/Ebb. It is usually a matter of load balancing between a Web server using some kind of IPC to distribute the load back to Ruby VMs running your Rails app.</p>
<p>Now we have mod_Rails. What&rsquo;s your opinion on having all those choices, do you have any particular recipe you like or it depends on each application&rsquo;s needs? Did you have time to test mod_Rails? I think Hongli Lai is doing great stuff in regards to things like mongrel_light_cluster and his efforts on making Ruby&rsquo;s GC more copy-on-write friendly, did you take a look at that?</p>
<p><strong>Chris Wanstrath:</strong> The nice thing about Engine Yard is they get to take care of all that stuff for me. So while I used to spend a lot of time benchmarking and playing with different solutions, like Mongrel vs Emongrel, I just let the experts take care of it so I can focus on Github..</p>
<p>So no, I haven&rsquo;t played with mod_Rails yet because I&rsquo;m not in the situation where I could deploy it even if I wanted to use it. Which is in my opinion the best situation to be in, and pretty much the reason mod_Rails was written.</p>
<p><strong>AkitaOnRails:</strong> And by the way, are you going to make any presentation at RailsConf this year?</p>
<p><strong>Chris Wanstrath:</strong> I am. I&rsquo;ll be talking about <em>&ldquo;Beyond cap deploy&rdquo;</em>, which will pretty much be an in-depth look at the Github architecture, and then I&rsquo;ll be on a panel with Ben Curtis, Geoff Grosenbach, P.J., and Tom about being a &ldquo;profitable programmer&rdquo; w/ side projects.</p>
<p><strong>AkitaOnRails:</strong> I am very pleased to have the opportunity to talk to you.</p>
<p><strong>Chris Wanstrath:</strong> Yes, you too. Thanks!</p>
]]></content:encoded><category>interviews</category><category>open-source</category><category>software-architecture</category></item><item><title>Chatting with Chad Fowler</title><link>https://akitaonrails.github.io/en/2007/05/07/chatting-with-chad-fowler/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/05/07/chatting-with-chad-fowler/</guid><pubDate>Fri, 04 May 2007 07:45:00 -0300</pubDate><description>&lt;h2&gt;Chatting with Chad Fowler&lt;span class="hx:absolute hx:-mt-20" id="chatting-with-chad-fowler"&gt;&lt;/span&gt;
&lt;a href="#chatting-with-chad-fowler" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://akitaonrails.s3.amazonaws.com/files/chadfowler.jpg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Last Tuesday (April, 24th) was a memorable day for me. I was able to have not only one, but two celebrities from the Ruby community. I interviewed Chad Fowler in the morning and then David Black in the evening. The original founders of the Ruby Central and two of the people most responsible for evangelizing Ruby back in 2001.&lt;/p&gt;
&lt;p&gt;Both are veterans of our community and they were very kind. As you well know, I am a Brazilian Rails advocate and our local community is still small, but I believe the turn of the tide is not so far ahead.&lt;/p&gt;</description><content:encoded><![CDATA[<h2>Chatting with Chad Fowler<span class="hx:absolute hx:-mt-20" id="chatting-with-chad-fowler"></span>
    <a href="#chatting-with-chad-fowler" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="https://akitaonrails.s3.amazonaws.com/files/chadfowler.jpg" alt=""  loading="lazy" /></p>
<p>Last Tuesday (April, 24th) was a memorable day for me. I was able to have not only one, but two celebrities from the Ruby community. I interviewed Chad Fowler in the morning and then David Black in the evening. The original founders of the Ruby Central and two of the people most responsible for evangelizing Ruby back in 2001.</p>
<p>Both are veterans of our community and they were very kind. As you well know, I am a Brazilian Rails advocate and our local community is still small, but I believe the turn of the tide is not so far ahead.</p>
<p>My goal is to have known people speak to our local community so they can be inspired and motivated to not just jump into Ruby or Rails, but to aim for a higher level on their personal careers.</p>
<p>So, I will first present Chad Fowler’s interview, and next time I will publish David’s. Without further ado, here’s Chad:</p>
<p><strong>AkitaOnRails</strong> : Well, not only software but I guess interviews have their own set of ‘Design Patterns’ as well. So, let me get rid of the ‘usual suspects’ before we get to the real juice. I personally like background history. How did you start in the computer world? I would guess you’re a self-learner programmer, one of the early hackers, is that right?</p>
<p><strong>Chad</strong> : You are right. I went to college to get a degree in music. I was a jazz saxophonist and “classical” composer. I got interested in computer programming, because I have always loved computer games, and I wanted to write my own. Now, many years later, I still haven’t written a computer game.</p>
 <!-- broken image, not found in S3: /files/197px-Richard_Matthew_Stallman.jpg -->
<p><strong>AkitaOnRails</strong> : No kidding. Would you mind to tell us when was it? Your appearance may be deceiving. When I see a picture of you, it reminds me of <a href="http://en.wikipedia.org/wiki/Richard_Stallman"target="_blank" rel="noopener">Richard Stallman</a>. I hope I am not aiming for a long shot. Was it in the era of the <a href="http://en.wikipedia.org/wiki/PDP_10"target="_blank" rel="noopener">PDP-10</a> stuff or was it more recent?</p>
<p><strong>Chad</strong> : haha. Very much more recent. I started programming in earnest only 11 years ago. I’ve always looked older than my age. Nobody ever said I looked like Richard Stallman before though. I actually don’t normally have long hair, but I’m growing it to donate to <a href="http://locksoflove.org"target="_blank" rel="noopener">http://locksoflove.org</a>.</p>
<p><strong>AkitaOnRails</strong> : Haha, that’s nice. And going directly to the point: how did you find out about Ruby? What is Ruby to you? What makes you excited about it?</p>
<p><strong>Chad</strong> : Having started as a musician and specifically a composer, I view computer programming as a creative endeavor. More of an art than an engineering discipline. I’m also a language geek, so I spend a lot of time exploring new (and unusual) programming languages. I discovered Ruby in 2000 during one of my Saturday language exploration sessions. I had actually planned to seriously focus on <a href="http://en.wikipedia.org/wiki/Smalltalk"target="_blank" rel="noopener">Smalltalk</a>, but I spent that Saturday learning Ruby and it derailed me from my Smalltalk learning.</p>
<p>Ruby was a perfect blend of pragmatism and beauty/idealism for me. I haven’t found anything since which <em>feels</em> as good as Ruby. For me, the feeling I get when programming is at least as important as other factors when selecting a language.</p>
<p><a href="http://www.mcbreen.ab.ca/SoftwareCraftsmanship/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/software_craftsmanship.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : I see. Have you ever read Pete McBreen’s <a href="http://www.mcbreen.ab.ca/SoftwareCraftsmanship/"target="_blank" rel="noopener">Software Craftsmanship</a>?</p>
<p><strong>Chad</strong> : Yes. I actually read that book on the plane to the first International Ruby Conference, which David Black, Dave Thomas, and I co-organized. Pete McBreen was at the conference and was one of the presenters. So I was able to get my book autographed. His thoughts on craftsmanship and apprenticeship are right in line with what I believe.</p>
<p><strong>AkitaOnRails</strong> : Me too. I have a feeling that most of the ‘hackers’ consider themselves <em>artists</em>. Do you think that’s the case? I believe you met great hackers along the way.</p>
<p><strong>Chad</strong> : I think he’s taken a somewhat extreme approach, and I’m afraid it’s a little more than what the industry can actually handle. It’s unfortunate that we can’t see more of this kind of thing in the industry. I would say that most of the great hackers do NOT consider themselves to be engineers. They might not all feel the extreme of being artists. Some think of software development as a craft, which I’d place somewhere in between art and engineering.</p>
<p><strong>AkitaOnRails</strong> : Very well said. And speaking of the community, I hear that before Rails, the Ruby community was very small and all of a sudden it exploded. Do you think Rails is growing up too fast? Is the Ruby community comfortable with this fast pace? Or is it not so?</p>
<p><strong>Chad</strong> : You’re right about the size (and pace) of the Ruby community before Rails. The first Ruby conference had 40 people at it. The 4th had 64 people. Not very fast growth. We sold out the 5th conference with 200 people and could have added more. There are certainly some growing pains with the explosion that happened with Rails, but I don’t think smart people in the Ruby community should complain. The explosion has brought us all into a situation in which we can work in our beloved language professionally. Until 2005, there were only a handful of Ruby programmers getting paid to work in Ruby full time outside of Japan.</p>
<p><a href="http://on-ruby.blogspot.com/2006/10/rubyconf-2006-implementers-summit.html"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/imp_summit_2.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : Right. RubyCentral is a very important institution in that matter. You’ve been responsible for many successful Conferences. How did you start it? And what are the values and ideas of RubyCentral?</p>
<p><strong>Chad</strong> : We started Ruby Central primarily to handle RubyConf. In 2001, Guy Hurst was organizing the first Ruby conference and had some personal obligations come up that made it impossible for him to finish the organization of the conference. So, Dave Thomas (of the <a href="http://www.pragmaticprogrammer.com"target="_blank" rel="noopener">Pragmatic Programmers</a>) stepped in to make sure the conference didn’t die when Guy stepped out.</p>
<p>He knew that a conference was an important milestone for the Ruby community. Dave enlisted David Black and myself to help lead the organization of the conference. After the first one, we realized it would make sense to establish a non-profit company to handle the conference in the future, which we did the following year.</p>
<p>As we’ve enjoyed more success in our events, we’ve started to branch out into other projects, including other conferences, sponsoring regional conference events, and funding “code fests”. As Ruby continues to grow, we hope to grow with it and to expand our role in the community.</p>
<p><strong>AkitaOnRails</strong> : Yes, I heard about Guy, but very little. Where is he now? What is he doing? And were you all friends before Ruby? You, David Black, Dave Thomas, Guy?</p>
<p><strong>Chad</strong> : I haven’t heard from Guy for several years. He was primarily a PHP developer, and I think that may still be the case. David, Dave, and I didn’t know each other before Ruby. We met on #ruby-lang on freenode back when there were only 12 people there on a regular basis. Since then, of course, we’ve all collaborated on many projects.</p>
<p><strong>AkitaOnRails</strong> : You’ve been traveling a lot, you do many workshops, keynotes. I know that if people attend to your presentations is because they do have some interest in the subject. But did you find ‘skeptics’ along the way? Do you think people still think of Ruby as something over-hyped? Or are people getting used to it as a real-world solution?</p>
<p><strong>Chad</strong> : I do still encounter skeptics. Most of the skeptics are Rails skeptics—-not Ruby skeptics. Rails is over-hyped. That’s a fact. It’s also a really powerful tool, so the hype is a good thing. Hype always turns <em>some</em> people off, but in this case it hasn’t turned enough people away that it is bad. I’m seeing more and more “uninteresting” uses of Rails and of just Ruby alone.</p>
<p>By &ldquo;uninteresting&quot;, I mean that companies are using it for their intranet applications and other <em>unsexy</em> non-Web 2.0 applications. That’s a sign of maturity and that we’re moving past the early adopters on the curve and into mainstream territory. Ruby and Rails are being used for large and small applications. The cool thing, from my perspective, is that it’s no longer news when a company decides to use Ruby. Back in 2004, it was a big deal anytime a company made the choice to go with Ruby.</p>
<p><strong>AkitaOnRails</strong> : I thought that the opposite was true: that Rails was used mainly as a startup resource to get to the market faster. Do you see traditional enterprises adopting Rails?</p>
<p><strong>Chad</strong> : The opposite was and is still true. Startups are using Rails to great effect. But, now I’m seeing a lot more traditional enterprise adoption. The profile of the companies I’ve been working with has been changing and getting more diverse. Topics like system integration are getting a lot more interesting to the customers I’m talking to.</p>
<p><strong>AkitaOnRails</strong> : At least here, I see that many IT managers and CIO’s still adopt the old IBM posture. If you asked a manager back in the 60’s: <em>“Why do you buy from IBM?&ldquo;</em>, he would answer: <em>“Because nobody gets fired buying from IBM”</em>. Now, we have another scenario: <em>“Why do you buy Java?&ldquo;</em>, <em>“Well, because nobody gets fired buying Java stuff”</em>. Do you think this scenario still holds true?</p>
<p><strong>Chad</strong> : I think it will always hold true in big companies. Big companies make decisions based on fear. It’s not just true in IT. It’s true in HR, manufacturing, and other functions in big business. Fear-driven decision making comes from the way big companies are inherently organized and from the way promotion and success are measured.</p>
<p>I’m not sure there’s a way around it, other than perhaps treating big companies like a huge collection of small autonomous companies. I’ve heard of successful experiments resembling this idea, but I haven’t investigated in detail.</p>
<p>The funny thing about this kind of decision making is that it focuses on <em>not failing</em> as opposed to <em>winning</em>. You’ll very rarely see a huge success in an environment like this.</p>
<p><a href="http://pragmaticstudio.com/railsadvanced/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/davemikechad.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : Yes, indeed. I suffer this daily. I like this subject so I will return to it again. But changing subjects a little bit. I believe your most recent published book is Pragmatic Programmers’ <a href="http://www.pragmaticprogrammer.com/titles/fr_rr/"target="_blank" rel="noopener">Rails Recipes</a>. I bought it as soon as it was released and I can tell that it’s an amazingly useful resource. I like the Recipes kind of book. Was there anything in the process of making it that you think was challenging or curious? Any tales about its making of?</p>
<p><strong>Chad</strong> : Thanks for the kind words. The thing about the book that I always want to get across is that it’s truly a “recipe” book. Most recipe-style books are nothing but complete references, artificially divided into recipe format.</p>
<p>The equivalent in cooking would be to have recipes on topics like <em>“How to throw a dash of salt into your food”</em>. Nobody needs a recipe on a granular topic like that. Recipes should teach you to make something you didn’t already know how to do.</p>
<p>That was my focus. I tried to make recipes that were really compositions of many ingredients. The biggest challenge in writing the book was that Rails is a moving target. As you know, writing a book against something that’s constantly changing is not easy. I had to spend a <em>lot</em> of time in the source of edge rails.</p>
<p><a href="http://www.pragmaticprogrammer.com/titles/fr_arr/index.html"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/advrailsrecipes.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : I know that, I also wrote a book that is already lagging behind (it was for 1.1). And you’re already preparing the <a href="http://www.pragmaticprogrammer.com/titles/fr_arr/"target="_blank" rel="noopener">Advanced Rails Recipes</a>. As you evolved since the first book, what do you think of the current Rails evolution? Is it happening too fast? Are people having time to grasp all the new stuff?</p>
<p><strong>Chad</strong> : I don’t think people have time to grasp the new stuff. Most people I talk to around the world still haven’t caught up with Rails 1.1. That’s an easy perspective to lose when, like you and me, you spend most of your time in the “alpha geek” Rails community.</p>
<p>Fortunately for us that are writing books, that means that out-of-date books are still valuable to “normal” Rails developers. I don’t think it’s bad that the masses can’t keep up with the evolution of Rails. It just means that the bleeding edge features are only being used by the bleeding edge developers. So far, Rails has stayed mostly backward compatible.</p>
<p>The interesting thing will be to see how the release of Rails 2.0 impacts the less-than-bleeding edge portion of the community. Rails 2.0 will introduce incompatibilities and will enforce new conventions/opinions on developers. I’m guessing it will be a messy and upsetting process, but we’ll get through it.</p>
<p><strong>AkitaOnRails</strong> : I read a recent blog post about a keynote that I guess you did in March. I don’t know if it were your words, but the <em>“Ruby is at a dangerous crossroads”</em> statement caught my eyes. I think so as well. I would love to see you elaborate on that.</p>
<p><strong>Chad</strong> : The primary reason I think we’re at a dangerous point in our path is this: Having been a niche player for so many years, we’ve had to kick and fight to defend our ground as a legitimate language choice. When you spend all of your time fighting, it burns its way into the community’s culture. Our default reaction to change is now defensive and argumentative. And, believing we’re on the cutting edge, we close our minds to suggestions from the outside world. This was OK when we were in defense mode, but now that we’re “winning” in terms of adoption, we have to actively change the culture of the community or else we run the risk of becoming closed-minded curmudgeons.</p>
<p><strong>AkitaOnRails</strong> : That old rant from DHH: <a href="http://www.loudthinking.com/arc/000584.html"target="_blank" rel="noopener">who wants to become mainstream?</a> Do you think he still has this opinion? Many people follow that rant.</p>
<p><strong>Chad</strong> : I think he still has that opinion, though he’s probably backing off to some extent, because we’re already becoming mainstream. I also happen to agree with him in some ways.</p>
<p><a href="http://dabbledb.com/blog/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/avi_bryant.jpg" alt=""  loading="lazy" /></a></p>
<p>Matz gave a talk at OSCON 2005 called <em>“It’s cool to be minor”</em>, talking about the advantages of not being mainstream. Avi Bryant, of Seaside fame, also vocally enjoys the niche status of <a href="http://www.squeak.org/"target="_blank" rel="noopener">Squeak</a> and <a href="http://www.seaside.st/"target="_blank" rel="noopener">Seaside</a>.</p>
<p>Looking back at RubyConf 2001, we had 40 people in attendance, several of whom were authors of the <a href="http://agilemanifesto.org"target="_blank" rel="noopener">Agile Manifesto</a>. Still, others were authors whose books I had read and enjoyed over the months leading up to the conference. It was a small group of experts. Small communities are like that. Larger communities, like large companies, have priorities and focuses that are different. Both are good, but for alpha geeks like DHH, smaller is probably better for the creative process.</p>
<p><strong>AkitaOnRails</strong> : Another phrase of the same blog post that caught my eyes was <em>“Ruby 2.0 has been vaporware for longer than Perl 6.”</em> It is very true. Ruby has been in 1.8 like forever. I believe that Rails was explosive in many ways. Over-exposure can be good or evil. You get famous, but you have to live up to it. Fortunately now I see lightning fast efforts as JRuby. What do you think of this situation? Can Ruby be doomed to be replaced by some alternative implementation, or Ruby 2.0 is real enough today?</p>
<p><strong>Chad</strong> : I don’t think Ruby 2.0 is doomed. I was actually quoting Matz when I said that Ruby 2.0 was vaporware. Matz gave a talk on Ruby 2.0 at RubyConf 2001 (when we were still in Ruby 1.6.x). JRuby has also been in development since 2000.</p>
<p>I believe Matz has organized the team the right way now and is making real progress toward Ruby 2.0. I’m expecting to see a beta release by the end of this year as he has promised. Keep in mind that Ruby 2.0 is actually 2 different things:</p>
<ol>
<li>a new VM (YARV)</li>
<li>a new language</li>
</ol>
<p>The new language has been Matz’s interest and focus. Now that we have someone officially working on the new VM, Matz is freed to evolve the Ruby language.</p>
<p><a href="http://www.atdot.net/yarv/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/ko1-and-matz.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : Sure, actually I feel that I saw both Ruby 2.0 and JRuby speeding up in the last year or so, more than in the previous years.</p>
<p><strong>Chad</strong> : Very true. JRuby is speeding up due to the efforts of Charles Nutter and Thomas Enebo, who have recently been hired by Sun to work almost exclusively on JRuby. They’re putting in a lot of effort and it shows.</p>
<p><strong>AkitaOnRails</strong> : Yes, I just saw <a href="http://ola-bini.blogspot.com/2007/04/jruby-099-released.html"target="_blank" rel="noopener">0.9.9</a> coming out yesterday. Amazing effort. I can picture them working overnight on this, it’s crazy. I am trying to have Charler Nutter interviewed as well. The local Java community will go nuts on this one.</p>
<p><strong>Chad</strong> : Yea, definitely. The JRuby guys are definitely heroes in the Java world.</p>
<p><strong>AkitaOnRails</strong> : Ruby is pretty much in childhood here in Brazil yet. It is taking a lot of effort trying to warm up the local community. At least from a distance I can see that the US and EU Ruby Community are growing very strongly and developing fast. You were there since the beginning. What do you think was the turning point for Ruby there? What did it take to make Ruby recognizable and respected?</p>
<p><strong>Chad</strong> : Two things. The first was the fact that many of the industry’s thought leaders were long-time advocates of Ruby. Dave Thomas, Andy Hunt, Martin Fowler. All of them were using Ruby long before it took off. This set the stage for the Rails explosion.</p>
<p>When Rails came out, the hype was backed by some very well respected names in software development. Rails was, of course, the second (and largest) thing that pushed us over the hump. Most importantly, it was the marketing efforts of David Heinemeier Hansson.</p>
<p>Truthfully, Europe is lagging far behind the US in terms of Ruby adoption. India and other similar locations are far behind Europe. I think it’s a natural progression based largely on the economies of each region. I would guess that Brazil will come along in time. You just have to wait for the wave to hit you.</p>
<p><strong>AkitaOnRails</strong> : Yes, the wait is really killing me :-) I see dozens of <a href="http://www.amazon.com/s/ref=nb_ss_gw/104-4550277-6092734?url=search-alias%3Dstripbooks&amp;field-keywords=ruby&#43;rails&amp;Go.x=4&amp;Go.y=11&amp;Go=Go"target="_blank" rel="noopener">Rails and Ruby books at Amazon</a>, and mine remains the sole Rails book here. It’s kind of sad. And it’s very hard to push the community forward because we have the very old <em>chicken-and-egg</em> situation: companies don’t want Rails because there’s no professionals available, and programmers don’t want to learn Ruby or Rails because companies are not demanding.</p>
<p><strong>Chad</strong> : This is exactly the situation in India. I think that’s largely economics-driven. It will come to you, but if your primary market is serving others’ IT needs at lower costs, you’re going to necessarily play it conservatively and go for volume—-not margin.</p>
<p><strong>AkitaOnRails</strong> : I spent a lot of time trying to understand that. Rails landed as a storm in the US. I can see the explosion. But it is very slow in other places of the world, like here. What is it so different in the US? I can’t believe it’s only coincidence.</p>
<p><strong>Chad</strong> : Like I said, I think it’s largely economics. Living in India attuned me to the fact that in developing countries, the focus is on economic survival and financial success. In the US, most software developers just want to have fun. Given our financial success as a nation, we have developed a greater sense of entitlement. So we, more than other countries, view our work as something that has to be enjoyable, and we are therefore more likely to experiment and push the boundaries.</p>
<p>We don’t in general spend time worrying about keeping our jobs compared to people in other countries, because we feel we can get another job whenever we like. In other countries, there’s more of an emphasis on employment being a service to the employer as opposed to the other way around. I think in terms of ethics, the position of the average US software developer is inferior to that of developers in other countries, but it fosters innovation.</p>
<p><a href="http://www.pragmaticprogrammer.com/titles/mjwti/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/mjwti_medium.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : You’re right on that. I’ll think more about it. And speaking of India. You wrote many things, but my favorite book is <a href="http://www.pragmaticprogrammer.com/titles/mjwti"target="_blank" rel="noopener">My Job Went to India</a>. I can totally see the motivation to write such a piece with all that overseas outsourcing stuff going on. I read it and I found myself at home because I already live up to many of your 52 ways, although I never did any of it to <em>“save my job”</em>. I just do the things I do because I enjoy it. When did you have the idea to jot down those ideas? Any particular motivation?</p>
<p><strong>Chad</strong> : Before I answer the question, I want to agree with you about <em>“saving your job”</em>. The title of the book was a mistake. <em>My Job Went to India</em> is really not about saving your job. It’s about creating a remarkable career for yourself.</p>
<p>I have spent a lot of time in India and elsewhere mentoring younger software developers on their careers. I’ve also done a lot of interviewing. Over time I’ve found myself explaining and motivating the same way over and over again. When I returned from India, I decided to leave my job at a big conservative company, which freed me to write without the constraints of intellectual property agreements weighting me down.</p>
<p>I talked to Dave Thomas about doing a book about how to do offshoring right, and it was Dave who actually turned the topic around and pointed out that I had a much larger audience which I could help by putting together thoughts on how to think about a career in this new global environment.</p>
<p><strong>AkitaOnRails</strong> : Unfortunately I see many people here going the usual way: graduating college, maybe taking one Java certification or two and then simply stopping. From then on they just live in their routine. They’d rather have a routine than having to make decisions – and living up to them. I try my best to mentor as many people as I can. Any advice for this current generation? I know the question is too broad (the theme of an entire book), but you probably have something that you say to every youngster that you see with a question mark in their foreheads.</p>
<p><strong>Chad</strong> : The only way to quickly sum it up is: have passion for what you do. Your work life is such a large portion of your total life, that you don’t want to spend it doing something you’re not passionate about. Don’t be afraid to take control of your career and to take chances. I would take that even as far as saying that you might have chosen the wrong field, and it’s never too late to realize that and make a change.</p>
<p><strong>AkitaOnRails</strong> : Nice, that’s my motto as well. Many people simply refuse to think that way because their reasoning goes like this: “things that I enjoy don’t make me earn enough to bring food on the table, so I have to do what I don’t like so that I can survive”. It’s a sad reasoning. I know I am very fortunate being able to just go the way I enjoy the most, but many people find it too difficult to switch careers or learn something new. Education is expensive in Brazil, unemployment is a reality. Unfortunately there’s not too much that I can do but to mentor as many as I can.</p>
<p><strong>Chad</strong> : Again, that’s an unfortunate reality outside the US, and probably another reason that the US is more innovative in the IT field. It <em>is</em> possible here to switch careers nearly whenever you like. And it’s much easier to get work based on merit and not credentials. So, I (for example) as a musician was able to build a career for myself in IT without having to go to university. I still have not taken a single computer programming course.</p>
<p><strong>AkitaOnRails</strong> : You mentioned that you spent time at India. Do you see this kind of reality there too? People so focused on surviving and not on enjoying their work?</p>
<p><strong>Chad</strong> : Yes, very much so. I would guess that the motivations behind professional life are very similar between India and Brazil.</p>
<p><strong>AkitaOnRails</strong> : Have you ever been in Brazil our met Brazilians?</p>
<p><strong>Chad</strong> : I have met Brazilians but not been in Brazil. I would love to visit, though!</p>
<p><strong>AkitaOnRails</strong> : And about communities again. The Java community is very strong in Brazil. The sponsorship of Sun and the many years in the development raised a very strong foundation here. I still see a lot of animosity between Java guys and everybody else. They invested a lot of time in a single technology and it seems natural for them to bash everything else. Do you see it happening there as well?</p>
<p><strong>Chad</strong> : I do. It’s a natural human tendency. And, if you think about it, Java, like Ruby , went through the same periods of having to sell itself early on as being a feasible technology. My fear is that the Ruby community now is like the early Java community, and that our fate is to become as closed and unaccepting of change and new ideas as many in the Java world have.</p>
<p><strong>AkitaOnRails</strong> : Ok, I am very happy that we could have this conversation. Thanks a lot!</p>
<p><strong>Chad</strong> : cool thanks!</p>
]]></content:encoded><category>interviews</category><category>ruby</category><category>open-source</category></item><item><title>Chatting with Geoffrey Grosenbach</title><link>https://akitaonrails.github.io/en/2007/04/21/chatting-with-geoffrey-grosenbach/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/04/21/chatting-with-geoffrey-grosenbach/</guid><pubDate>Thu, 19 Apr 2007 19:33:00 -0300</pubDate><description>&lt;h3&gt;Chatting with Geoffrey Grosenbach&lt;span class="hx:absolute hx:-mt-20" id="chatting-with-geoffrey-grosenbach"&gt;&lt;/span&gt;
&lt;a href="#chatting-with-geoffrey-grosenbach" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;img src="https://akitaonrails.s3.amazonaws.com/files/geoffrey.gif" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://akitaonrails.github.io/pages/drnic"&gt;Dr Nic&lt;/a&gt; interview was a huge success and getting to know and exchange ideas with people as smart and intelligent is very addicting. So, I was again very fortunate to get in touch with &lt;strong&gt;Geoffrey Grosenbach&lt;/strong&gt; , from &lt;a href="http://www.topfunky.com/"target="_blank" rel="noopener"&gt;Topfunky Corporation&lt;/a&gt;. He was very kind in accepting my invitation for this interview and sharing some of his experiences with us, Brazilians.&lt;/p&gt;
&lt;p&gt;I am trying hard to get to know and interview more celebrities from our industry, so hang on there, because we may have more surprises.&lt;/p&gt;</description><content:encoded><![CDATA[<h3>Chatting with Geoffrey Grosenbach<span class="hx:absolute hx:-mt-20" id="chatting-with-geoffrey-grosenbach"></span>
    <a href="#chatting-with-geoffrey-grosenbach" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://akitaonrails.s3.amazonaws.com/files/geoffrey.gif" alt=""  loading="lazy" /></p>
<p>The <a href="/pages/drnic">Dr Nic</a> interview was a huge success and getting to know and exchange ideas with people as smart and intelligent is very addicting. So, I was again very fortunate to get in touch with <strong>Geoffrey Grosenbach</strong> , from <a href="http://www.topfunky.com/"target="_blank" rel="noopener">Topfunky Corporation</a>. He was very kind in accepting my invitation for this interview and sharing some of his experiences with us, Brazilians.</p>
<p>I am trying hard to get to know and interview more celebrities from our industry, so hang on there, because we may have more surprises.</p>
<p>It was a very long conversation, which I enjoyed a lot. We discussed a lot about him, his projects, the Ruby on Rails community and things to come. So, let’s get started.</p>
<h3>Who’s Geoffrey?<span class="hx:absolute hx:-mt-20" id="whos-geoffrey"></span>
    <a href="#whos-geoffrey" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>AkitaOnRails</strong> : We know the name Geoffrey Grosenbach from the <a href="http://podcast.rubyonRails.org/"target="_blank" rel="noopener">Rails Podcast</a> and <a href="http://peepcode.com/"target="_blank" rel="noopener">PeepCode</a>. But again, who is Geoffrey Grosenbach? Where are you from? How did you get started at Rails?</p>
<p><strong>Geoffrey</strong> : Who am I? That’s a big question, but I saw that you asked Dr. Nic, so I was expecting it. ;-) I got started in Rails about 2 years ago when I was living in Taiwan. I was a technology coordinator at an American school and wanted to keep up on what was happening in the web development community. I also had a few freelance gigs and thought, <em>“I’ll try out Rails on one of them.”</em> The client didn’t care what technology was used and it was a great opportunity to use Rails on a real project. That project was eventually abandoned, but I learned a lot. I started by reading through the entire online docs for Rails, which is probably something I should do again! At any rate, previously I worked for several startups, initially using Java and then Microsoft technologies (I live in Seattle), and also Perl, PHP, and the like. My college degree is actually in <strong>Philosophy</strong> , though, which I’ve never made a cent from (but it was a great topic to study).</p>
<p><strong>AkitaOnRails</strong> : Nice. And what’s the deal about Taiwan? How long did you live there? It was just for some particular project?</p>
<p><strong>Geoffrey</strong> : I lived there for a little less than 2 years. I wanted to live outside the USA for a while and a few friends had been encouraging me to come work at their school. There were some dry years in 2002-2003 where it was tough to get a good web development job here, so I took the opportunity. I taught a few computer-related classes to teenagers and also purchased equipment and kept the (Windows 98) network running.</p>
<p><strong>AkitaOnRails</strong> : The post-<a href="http://en.wikipedia.org/wiki/Dot-com_bubble"target="_blank" rel="noopener">Bubble</a> era. You mentioned startups. Any known big names? And Jesus, Windows 98 in 2003? :-)</p>
<p><strong>Geoffrey</strong> : Yeah, it was pretty sad. Fortunately it wasn’t Windows ME! I upgraded the whole network to XP while I was there. I also ran a few Linux servers for firewalls and such, and convinced the school to buy me a dual screen Mac. But as for startups….</p>
<p>I wrote data-mining type software for a company called Project Guides that was later bought by Onvia. Onvia was a pretty big company and sold computer equipment online before they went public. But now they have completely changed and are in the government contracting business.</p>
<p>It was a fun job because I basically created the position. I was hired to scan newspaper articles and run OCR software to pull out the text. (as a college internship). I thought, <em>“Couldn’t this be done online?”</em> So I researched the existing sources and wrote a proof-of-concept bot that would visit government project announcement sites and catalogue upcoming projects that companies could bid on. There was no RSS, so it was a lot of parsing of HTML to pull the data out.</p>
<p><strong>AkitaOnRails</strong> : And all this in the Internet Bubble era? How bad did the burst of the bubble affected you, your life and your plans?</p>
<p><strong>Geoffrey</strong> : Yeah. Well, with a degree in philosophy, I didn’t expect to be very wealthy. When I got that job doing programming it was a huge surprise. But I love to program (my first programming class was learning BASIC in 4th grade in the mid 80’s).</p>
<p><strong>AkitaOnRails</strong> : And just out of curiosity, what led you to a Philosophy degree instead of, let’s say, Computer Science?</p>
<p><strong>Geoffrey</strong> : I’m an avid <strong>self-learner</strong> and I felt that I would benefit more from learning many of the topics on my own instead of going through a program. After I graduated, many of my friends with CS degrees would come to me and ask how to do basic things like connect to a database or write a dynamic web page. I guess I just preferred to learn on my own, on the job, instead of in a class.</p>
<p><strong>AkitaOnRails</strong> : Haha, I completely understand that. I have a similar situation. I’m a self-learner myself. But back to the first question. Isn’t it a little bit unusual to pick up Ruby as an option like 2 years ago? Or was it already famous there?</p>
<p><strong>Geoffrey</strong> : I had heard about Ruby at about the time of the <a href="http://www.ddj.com/dept/webservices/184404436"target="_blank" rel="noopener">famous Dr Dobbs article</a> in 2000 or 2001. I thought <em>“That’s weird. Calling methods on a bare integer?”</em> I wish I had tried it out more then, and I don’t know why I didn’t. I was trying other languages like <a href="http://en.wikipedia.org/wiki/REBOL"target="_blank" rel="noopener">REBOL</a> and learning C and Java, of course. But why Ruby? I was doing some client work and stumbled upon <a href="http://www.basecamphq.com/"target="_blank" rel="noopener">Basecamp</a>. From there I learned about Rails and decided to try it out. Also, I wasn’t working for a company that required a particular language. The school in Taiwan used Cold Fusion and I wrote some sysadmin scripts in Perl, but I could use whatever I wanted to.</p>
<p><strong>AkitaOnRails</strong> : Do you work only on Rails nowadays? Maybe it’s time to ask about <a href="http://www.topfunky.com/"target="_blank" rel="noopener">Topfunky</a>. What can you tell us about it?</p>
<p><strong>Geoffrey</strong> : Well, the job in Taiwan was on a 2-year contract. So I had to decide whether or not to sign on for another 2 years. I decided to come back to Seattle and that seemed like a good time to try to get freelancing gigs before applying to other jobs. Ironically, one of the jobs I did apply to would have sent me back to Onvia to write the next generation of bot software for them (as a subcontractor).</p>
<p>So I forget the exact series of events, but I started my <a href="http://nubyonrails.com/"target="_blank" rel="noopener">blog</a> and also got a small freelancing gig doing Rails. It’s been 100% Rails since then, mostly for <a href="http://pnn.com/"target="_blank" rel="noopener">PNN</a>, a company near San Francisco. Actually, I’ve been working pretty consistently for PNN for about the last year and a half. But I’ll be going fulltime with PeepCode in the next month or two.</p>
<p><strong>AkitaOnRails</strong> : I was gonna ask you that. Seems like <a href="http://peepcode.com/"target="_blank" rel="noopener">PeepCode</a> is very successful now.</p>
<p><strong>Geoffrey</strong> : Oh, yeah, part of the deal was that I went to a Seattle Ruby Brigade meeting in the summer of 2005 that happened to be at Amazon.</p>
<h3>The Rails Podcast<span class="hx:absolute hx:-mt-20" id="the-rails-podcast"></span>
    <a href="#the-rails-podcast" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><a href="http://podcast.rubyonrails.org/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/railspodcast.png" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : You started it all together? The blog, the podcast, the screencasts?</p>
<p><strong>Geoffrey</strong> : The blog first. I wrote the <a href="http://nubyonrails.com/pages/sparklines"target="_blank" rel="noopener">Sparklines library</a>, inspired by a handout left on the table at Amazon. Then I did a few interviews for the podcast and eventually took that over. PeepCode is only about 6 months old, but has done much better than I ever expected it would.</p>
<p><strong>AkitaOnRails</strong> : I haven’t listened to all of the <a href="http://podcast.rubyonrails.org/"target="_blank" rel="noopener">Rails Podcast</a> yet. Who was your first guest? Where did this interview idea come from?</p>
<p><strong>Geoffrey</strong> : I didn’t start it, actually. <a href="http://rubyi.st/"target="_blank" rel="noopener">Scott Barron</a>, of the Rails core team did, based on a dare from Heinemeier Hansson. He interviewed DHH and then Dave Thomas, and then a month went by. I wrote to him and asked if he would publish an interview if I did one.</p>
<p>I’ve always been interested in recording and audio. Then I ended up doing 43 more and still going strong! My first guest was Thomas Fuchs, of <a href="http://script.aculo.us/"target="_blank" rel="noopener">Scriptaculous</a>. Honestly, the sound quality was horrible initially. And I was a bit shaky on the interviews, but I’ve learned a lot in the process.</p>
<p><strong>AkitaOnRails</strong> : Your <a href="http://podcast.rubyonrails.org/programs/1/episodes/jack_dorsey_and_alex_payne_of_twitter"target="_blank" rel="noopener">last podcast episode</a> was about Twitter, Alex Payne and the discussion around the scalability problem. I still didn’t have time to listen. How did it go? Is everything settled down already? They are not dumping Rails, are they? :-)</p>
<p><strong>Geoffrey</strong> : I’m surprised that the Twitter issue has been such a big deal lately. There was that interview on a blog with Alex Payne and then the response from DHH, and it blew up from there. Hopefully this interview will command as much press as that one did. ;-) The podcast I did with Alex and Jack Dorsey, creator of Twitter, was pretty civil.</p>
<p><strong>AkitaOnRails</strong> : Exactly, I’ve been <a href="http://www.akitaonrails.com/articles/2007/04/15/a-polemica-twitter"target="_blank" rel="noopener">following</a> the flow of the events and it blew me away. But are the Twitter guys upset about all this fuss around them?</p>
<p><strong>Geoffrey</strong> : They talked about the idea, how it took only 2 weeks to develop the first version. And briefly mentioned that they were having some scaling problems, which they were fixing. From comments by Blaine, their lead developer, they have been very open about it. They don’t seem to be too upset and have supported Rails throughout, while being honest about the issues they are tackling.</p>
<h3>Rails Community<span class="hx:absolute hx:-mt-20" id="rails-community"></span>
    <a href="#rails-community" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><a href="http://conferences.oreillynet.com/rails/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/railsconf.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : And abruptly changing subjects, what about the conferences. RubyConf, RailsConf, US, EU, have you attended all of them?</p>
<p><strong>Geoffrey</strong> : I’ve been fortunate to have attended many of them, yes. RubyConf 2005 and 6. RailsConf Chicago and London. I’ll be at Rails Conf Portland this year, and also Berlin. And I am going to <a href="http://www.goruco.com"target="_blank" rel="noopener">GoRuCo</a> in NYC tomorrow. I’ve missed some of the regional ones, such as the one in Salt Lake City and the SDForum.</p>
<p><strong>AkitaOnRails</strong> : That’s the occasion where you do the podcasts? You hunt them all down and record them? Is that how it works? :-)</p>
<p><strong>Geoffrey</strong> : I have always said that if I couldn’t afford the conference, I would just go for the afterparties! It’s great to meet people in person. I try to do as many as possible in person. Recording over Skype is a great option, but the sound quality is often poor. I like the <em>on-the-spot</em>, journalistic feel of doing it in person. And I just got a great little hand-held recorder that I take everywhere with me (the Zoom H4).</p>
<p><strong>AkitaOnRails</strong> : Yes, that’s for sure, the afterparties! And I know the opinions will be biased in favor of Rails, but did you find any ‘skeptics’ between the audiences at the conferences? Do you feel they’re having a hard time learning or even using Rails at work? What’s the most usual good things or complaints you hear?</p>
<p><strong>Geoffrey</strong> : Well, if someone is paying US$1000 or more to fly to a conference, buy admission, and hotel, they are probably not going to be a skeptic. But there is a great mix of people, some of whom are just learning about Rails. There are definitely some difficult parts of learning Rails, or at least parts that are unconventional. That’s what I try to cover on PeepCode.</p>
<p><strong>AkitaOnRails</strong> : Are most of the programmers attending the conferences switchers, or do you see people starting their career going directly into Rails? Does Rails still hold the novelty status or is it well established already there in the US?</p>
<p><strong>Geoffrey</strong> : Still novelty, I think. I’ve written to a local college and offered to give a presentation to their CS classes on Rails. They never wrote back. I think a lot of it is up to students to stay current and learn it on their own. Students write to me and say “Instead of going to a movie on Friday night, I bought a PeepCode and learned about Rails”. Which is kind of surprising! I also think that there are a lot of people who want to use it but are in a job where they can’t. But there is definitely more demand than there are programmers. So at least for now, people who know Rails can benefit from the novelty status.</p>
<p><strong>AkitaOnRails</strong> : And are programmers getting used to concepts like <em>“Convention over Configuration”</em> or even the new RESTful approach of Rails 1.2? What do you think?</p>
<p><strong>Geoffrey</strong> : Going into a bit of detail here, I think there’s a huge disconnect between people on the “front edge” of Rails who use <a href="http://dev.rubyonrails.org/"target="_blank" rel="noopener">trunk/edge</a> Rails all the time, and those who are just learning and use the official releases. Even now, some people talk as if we’ve moved completely to the /articles/custom_action syntax instead of /articles;custom_action. So there are many people trying to learn Rails, or just get a product out the door that they have been working on for 6 or 9 months. For those people, there’s a lot of learning about the current styles that is difficult. Not everyone can rewrite their whole app every time the syntax changes. But the general ideas of Rails are leaking out into other frameworks, so I think people are becoming more familiar with the ideas, especially of REST. It depends on the person, of course.</p>
<h3>Learning Rails<span class="hx:absolute hx:-mt-20" id="learning-rails"></span>
    <a href="#learning-rails" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><a href="http://www.holovaty.com/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/adrianholovaty.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : Having made several podcasts, blogs and the teaching material of PeepCode. Where do you feel people are having the most difficult times about Rails? Where are they getting stuck at? Many people I know are a little bit afraid about the terseness of the syntax (mostly are Java programmers) and the lack of compilation (static typing).</p>
<p><strong>Geoffrey</strong> : Two things,</p>
<ol>
<li>The magic that goes on behind the scenes. In <a href="http://www.djangoproject.com/"target="_blank" rel="noopener">Django</a>, for example, there’s a more explicit connection between the templates being rendered and the variables being passed. With Rails, there is a benefit of having things happen automatically, but it’s also confusing.</li>
<li>ActiveRecord. It’s still the biggest part of Rails and the thing that attracts people, even though there are other ORM’s out there. I think it’s all about the user interface and learning to take advantage of what’s there without getting frustrated by what’s going on under the covers. For example, I was debugging a weird issue with <em>validates_uniqueness_of</em> last night. I still don’t know what was going on, and it may have been a problem with how late it was, but the error was deep inside active record somewhere. If someone was just learning Rails and expecting things to work smoothly all the time, that would be really confusing.</li>
</ol>
<p><strong>AkitaOnRails</strong> : Were you using edge? or the stable release?</p>
<p><strong>Geoffrey</strong> : Stable. But any programming project is going to encounter those kinds of issues. It’s just that people expect Rails to be 100% smooth sailing, sometimes (including me).</p>
<p><strong>AkitaOnRails</strong> : Java was like that back in the mid 90’s. Now people are cleverer about it’s behavior. And speaking of Django, I remember that you interviewed <a href="http://podcast.rubyonrails.org/programs/1/episodes/adrian_holovaty"target="_blank" rel="noopener">Adrian Holovaty</a>. He seems like a nice guy. How did you invite him? A Python guy talking in a Ruby show. And have you been using Django? I liked it a lot.</p>
<p><strong>Geoffrey</strong> : Well, I’m interested in seeing other perspectives on languages and frameworks. I think that’s part of what attracted me to Ruby. Previously, one of the most popular interviews was with <a href="http://smallthought.com/avi/"target="_blank" rel="noopener">Avi Bryant</a>, of <a href="http://www.seaside.st/"target="_blank" rel="noopener">Seaside</a> and <a href="http://www.dabbledb.com/"target="_blank" rel="noopener">DabbleDB</a>. So I think people like hearing from someone outside Rails every once in a while. I was in Chicago for RailsConf, and knew that Adrian lived there. So I met him at his office on Sunday morning. It was a great chat, although I understand Django a bit better now so I would ask different questions if I did it again. That’s still the most-downloaded interview, after the one with DHH.</p>
<p><strong>AkitaOnRails</strong> : No kidding! I tell colleagues all the time: <em>“don’t be limited to one thing only. Most of all, don’t be religious trolls!”</em> I once made a joke: <em>“you all sound like Sauron, one framework to rule them all, and in the darkness, bind them!”</em> :-) Do you see people like that there as well? I hope they are diminishing in favor of a more open-minded generation.</p>
<p><strong>Geoffrey</strong> : Strangely, many open source programmers approach software like a marketing department would. <em>“We need market share!”</em> Or religiously, thinking that you have to choose one and stick with it. But fortunately web services and remote API’s are changing that.</p>
<p><strong>AkitaOnRails</strong> : Yes, it’s all about the APIs, <em>“if it’s not an open API, I’m not using it”</em>. Don’t remember where I heard that motto.</p>
<p><strong>Geoffrey</strong> : Many people have a blog in Rails that imports delicious links from their servers running PHP, that tracks its stats from Google, running Python or whatever Google Analytics runs on. So there are many tools and they are good at different things. And by using others, you can loot their best ideas!</p>
<p><strong>AkitaOnRails</strong> : I guess, it’s one of the most compelling things about all this “Web 2.0” talking. Not only the social networking aspect, but also the ease of <strong>interoperability</strong>.</p>
<p><strong>Geoffrey</strong> : I’ve been using <a href="http://haml.hamptoncatlin.com"target="_blank" rel="noopener">HAML</a> for the last week, and I love the syntax, which is very YAML-like. Culturally, we do that, so it shouldn’t be a surprise that programming languages can do it, too.</p>
<h3>Personal Projects and Discipline<span class="hx:absolute hx:-mt-20" id="personal-projects-and-discipline"></span>
    <a href="#personal-projects-and-discipline" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>AkitaOnRails</strong> : So, how’s your life with so many things to do, places to go and people to meet? Conferences, Topfunky, Peepcode, podcasts, interviews. How do you organize your many activities? Many people I know complain that they <em>“don’t have enough time to learn new things”</em>, as an excuse to not learn Rails or whatnot. Any tips for the audience?</p>
<p><a href="http://www.zedshaw.com"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/zedshaw.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>Geoffrey</strong> : My model for personal organization and process refinement is Zed Shaw. I still need to interview him about it, but he keeps stats on how many bugs he writes, and then changes his workflow when it gets above a certain number. I’m not that smoothly engineered, but I do tweak my tools to get the most benefit. I use a few different to-do lists and project management systems (backpack, my own: <a href="http://theonlineceo.com/"target="_blank" rel="noopener">The Online CEO</a>). Mostly it’s trying to be aware of my own skills, needs, and mental stamina!</p>
<p>A problem I’m trying to figure out is how to maintain an open source project. I start a bunch of things and get patches from people, but don’t have time to actually apply and debug them, or rewrite them to work like I think they should. I’m thinking of running an open <a href="http://subversion.tigris.org"target="_blank" rel="noopener">svn</a> server where anyone can commit. Open source without the responsibility to keep a project going! ;-)</p>
<p><strong>AkitaOnRails</strong> : You need to subcontract a <em>maintainer</em> :-) Nothing can be committed unless it goes through a peer review or a more serious test suite.</p>
<p><strong>Geoffrey</strong> : Yeah, the problem is finding a maintainer who has free time. But it’s great to have a project that actually makes money, because it makes priorities clearer.</p>
<p><strong>AkitaOnRails</strong> : By the way, what open source project?</p>
<p><strong>Geoffrey</strong> : Well, I have a pile of 30 patches to <a href="http://nubyonrails.com/pages/gruff"target="_blank" rel="noopener">Gruff</a> that I haven’t had time to commit. And even some of my other Rails plugins and documentation, like the Capistrano recipes I posted for Dreamhost and TextDrive. I don’t even host Rails apps there anymore, so it’s hard to be motivated to maintain them. My wife loves to clean out the house and put a “Free” pile in front of the house. Usually, she can get rid of a pile of 20 or 30 objects in 24 hours that way. I need an open source version of that. ;-)</p>
<p><strong>AkitaOnRails</strong> : Oh, that’s a nice subject I was almost forgetting: your open source projects. I understand you maintain some. Which is the one people like the most?</p>
<p><strong>Geoffrey</strong> : Gruff is definitely the most popular. I enjoy writing graphical libraries, and use it in many of my own projects.</p>
<p><strong>AkitaOnRails</strong> : Many people here probably are not familiar with Gruff. How would you present it?</p>
<p><strong>Geoffrey</strong> : I started Gruff in the fall of 2005. Many people were on IRC or blogs saying <em>“Where’s a good Ruby graphing library? I can’t find any.”</em> So I was watching a movie one night and had my laptop. I started thinking about what kind of graphing library I would want to use, how the API would work, etc. By the end of the movie, I had a good start. So it does bar graphs, line graphs, pie, and a few others. It uses <a href="http://rmagick.rubyforge.org"target="_blank" rel="noopener">RMagick</a>, which is the biggest problem. It’s hard to install all the dependencies. Ryan Davis, here in Seattle, wrote a pure Ruby PNG library. I’m hoping to use that to write a simple graphing library that’s all ruby.</p>
<p><strong>AkitaOnRails</strong> : Yes, I heard about it. I hear that it’s more stable than <a href="http://www.imagemagick.org"target="_blank" rel="noopener">ImageMagick</a> (without the memory leaks)</p>
<p><strong>Geoffrey</strong> : Actually, he has a few different ones in development. ImageScience does resizing. His separate png library can do drawing and render simple fonts.</p>
<h3>Beyond Ruby<span class="hx:absolute hx:-mt-20" id="beyond-ruby"></span>
    <a href="#beyond-ruby" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>AkitaOnRails</strong> : So, have you ever been in contact with Charles Nutter, Ola Bini or anyone from the JRuby team? Are you following this subject? Do you have any opinion or heard any Java programmer talk about it?</p>
<p><strong>Geoffrey</strong> : I <a href="http://podcast.rubyonRails.org/programs/1/episodes/Railsconf_europe"target="_blank" rel="noopener">interviewed</a> Charles Nutter at RailsConf in London, a few days after they started working for Sun. I think it’s very exciting to see that project getting near to completion. The interoperability with Java will be a huge boost for existing Java projects. I’m also excited about the <a href="http://rubini.us/"target="_blank" rel="noopener">Rubinius</a> project, by Evan Phoenix here in Seattle.</p>
<p><a href="http://blog.fallingsnow.net/rubinius/"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/evanphoenix.jpg" alt=""  loading="lazy" /></a></p>
<p>The early culture around Ruby in Japan involved a lot of experimentation and hacking on the Ruby interpreter itself. I’m hoping that Rubinius will make that possible for people who want to hack in Ruby itself. And will probably be faster and more maintainable, too. It also has some great features for introspection. Even methods themselves are objects in Rubinius, with some more features than Ruby has now.</p>
<p><strong>AkitaOnRails</strong> : It’s one of the obstacles the JRuby guys are facing. Do you see a stronger exchange of assets between the projects? Together with XRuby, maybe?</p>
<p><strong>Geoffrey</strong> : They are definitely working together. I know that all the alternate implementers met at RubyConf in Denver last fall. And I think they may even have a mailing list.</p>
<p><strong>AkitaOnRails</strong> : And with all this turmoil around the community, what do you think are the most exciting developments going on?</p>
<p><strong>Geoffrey</strong> : PeepCode, of course!</p>
<p><strong>AkitaOnRails</strong> : hahaha, of course! :-)</p>
<p><strong>Geoffrey</strong> : Seriously, I think there are so many great projects that it’s hard to keep track of them all.</p>
<p><strong>AkitaOnRails</strong> : You’re right, it wouldn’t be even fair to pin point just one or two. I was going to ask who’s your all time favorite guest at the podcast, but it would not be fair as well. So, instead I’ll ask: have you ever come across some funny or curious situation during all those interviews? Something that stood out?</p>
<p><strong>Geoffrey</strong> : I love being able to document Ruby history. It was great to <a href="http://podcast.rubyonrails.org/programs/1/episodes/yukihiro_matsumoto"target="_blank" rel="noopener">interview Matz</a>, and have him translated from Japanese. <a href="http://podcast.rubyonrails.org/programs/1/episodes/jim_weirich"target="_blank" rel="noopener">Jim Weirich</a> is really insightful. Interviewing <a href="http://podcast.rubyonrails.org/programs/1/episodes/railsconf_2006_marcel_molina_and_sam_stephenson"target="_blank" rel="noopener">Marcel Molina and Sam Stephenson</a> together was great. Marcel did most of the talking, but when Sam spoke it was just in these concentrated, concise insights. He would be a great speechwriter, and the speech would only have to be 2 minutes long to communicate everything effectively.</p>
<p><strong>AkitaOnRails</strong> : The Core Team, yes. I remember that. He <em>HAS</em> to be concise: he writes a <a href="http://www.prototypejs.org/"target="_blank" rel="noopener">JavaScript library</a> that has to load fast even in a narrow-band connection :-)</p>
<p><strong>Geoffrey</strong> : Recording a ‘bootleg’ of the <a href="http://podcast.rubyonrails.org/programs/1/episodes/sxswi_why_the_lucky_stiff"target="_blank" rel="noopener">why the lucky stiff concert</a> at SXSW 2005 was a lot of fun.</p>
<p><strong>AkitaOnRails</strong> : SXSW, <a href="http://2007.sxsw.com/"target="_blank" rel="noopener">South by Southwest</a>. Brazilians are not aware of this event. Can you quickly describe it? Who meets there, what’s it all about?</p>
<p><strong>Geoffrey</strong> : Ah, it’s once a year in Texas. It’s part of a music and film festival, both of which are much bigger than the web development part. But almost every web developer who has written a book or has a popular blog is there (At least in English). It’s only about 3 days long, but it’s a fun time.</p>
<p><strong>AkitaOnRails</strong> : I know many podcasters go there. Did you meet the guys from Revision3, TWiT, C|Net, Podshow and others? Don’t you have a Podcast conference in the US as well? Many Brazilians are only starting to grasp the beauty of podcasts.</p>
<p><strong>Geoffrey</strong> : I haven’t been to any podcast conferences. I know a few other podcasters from Boagworld Podcast, Web 2.0 Show, but not many. I got an iPod video at Christmas and started subscribing to more since then, now that I have space to carry them all. I like Dan Benjamin’s Hivelogic Radio Show some video podcasts, like ZeFrank. I like more journalistic, in the streets podcasts rather than overly produced ones.</p>
<p><strong>AkitaOnRails</strong> : Nice suggestions for our readers. Let’s jump to one last subject before I bury you with so many questions. What about the Mac? Why are Railers so into the Macs? :-) (I am a Mac user, by the way, but it’s always good to hear from others)</p>
<p><strong>Geoffrey</strong> : I think Ruby has a great user interface for programmers, and people who like that sometimes like Macs, too. I think that as Ruby becomes more popular, there will be more content and help for people using it on Windows. My step dad was a teacher, so I’ve used Apple equipment since 1983. I feel that I live in a parallel universe to go to a Ruby conference and see so many Macs.</p>
<p><strong>AkitaOnRails</strong> : I was surprised as well. And probably everyone that got there was caught off guard. Or weren’t they? Is this a Ruby thing, or it all started with Rails?</p>
<p><strong>Geoffrey</strong> : I’m not sure. TextMate is definitely a factor, and the lightweight, <em>don’t need an IDE</em> philosophy of Rails. And now that people can make a good income writing Ruby code, it makes the price of Macs a non-issue.</p>
<p><strong>AkitaOnRails</strong> : Jason Fried and DHH surely helped this matter. Looks like Apple will release Rails pre-configured in Leopard (when it’s finally released next October).</p>
<p><strong>Geoffrey</strong> : I’m also interested in the <a href="http://rubycocoa.sourceforge.net/doc/"target="_blank" rel="noopener">Ruby integration with Cocoa</a> for those writing Mac desktop apps. It’s crazy that Java is being abandoned for that on the Mac, but Ruby will have bindings that ship with Leopard (I think).</p>
<p><strong>AkitaOnRails</strong> : Are you an Objective C programmer as well? I hear that the Ruby integration with Cocoa will be stronger in Leopard.</p>
<p><strong>Geoffrey</strong> : I’ve done a little bit. I experimented with OpenGL quite a bit, a few years ago. So I wrote a simple 3D game in OpenGL and Objective-C.</p>
<p><strong>AkitaOnRails</strong> : Java is being abandoned because Sun was never good to Apple. Linux, Solaris and Windows were all supported directly by Sun. I think I have recollections that Apple had to make their own JVM and support it all by themselves.</p>
<p><strong>Geoffrey</strong> : Right, and it was always a bit slower than the other implementations. Objective-C is getting more automated memory management, if I remember correctly. So maybe Ruby integrating with Mac desktop apps will have a chance to do well.</p>
<p><strong>AkitaOnRails</strong> : Precisely. Maybe Open Java will make things easier in a future Mac OS X iteration. Who knows. And speaking of the future, what are your plans for the future of your projects?</p>
<p><strong>Geoffrey</strong> : I’m going to be working on PeepCode fulltime. I shouldn’t say “this summer” because I think you’re about to enter winter.</p>
<h3>PeepCode<span class="hx:absolute hx:-mt-20" id="peepcode"></span>
    <a href="#peepcode" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><a href="http://www.peepcode.com"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/peepcode.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : Haha, yes, exactly. I personally like PeepCode, but I never heard of anyone else here buying it. Would you make translated versions?</p>
<p><strong>Geoffrey</strong> : A few publishers approached me and wanted to distribute it, but I really want to stay independent for as long as possible, and I think I have some great ideas that they wouldn’t have supported as strongly. I started talking to someone about Japanese translations. I’ve gotten a few reviews in Portuguese, though maybe not from Brazil.</p>
<p><strong>AkitaOnRails</strong> : Wow, count me on that if you ever plan on a Brazilian Portuguese translation ;-)</p>
<p><strong>Geoffrey</strong> : Great! I’d seriously like to try that. I’m starting to branch out into topics that might have broader appeal. I’ll be releasing “JavaScript with Prototype” next week. I definitely want to release a Rails-specific episode every month, but I hope to add others on a variety of web development topics, too.</p>
<p><strong>AkitaOnRails</strong> : Now, that is cool. Instead of focusing on Rails details, you will broaden the subjects. I bought only the first 3 screencasts yet. Have you ever done something on Mongrel or deployment and optimization procedures?</p>
<p><strong>Geoffrey</strong> : I did one on Capistrano, and also one with Zed Shaw on benchmarking with httperf. There’s also one on Page, Action, and Fragment caching. I’m also hoping to cover other topics that are barely covered anywhere, like scaling with memcached and mogilefs.</p>
<p><strong>AkitaOnRails</strong> : I <em>HAVE</em> to buy those. To let everybody here knows: how are the pricing models?</p>
<p><strong>Geoffrey</strong> : It’s $9 for a single show (they last 45-90 minutes, depending on the topic). You can buy 5 or 10 for a discount (US$7/each if you buy 10). I’m also rolling out team pricing, so you can buy at a discount for a development team of 5 or 10 people. And I’ll be giving out free coupons on my blog and elsewhere.</p>
<p><strong>AkitaOnRails</strong> : And what’s the size of each episode? How many episodes do you have so far? You mentioned Zed, so you’re not the loner host anymore?</p>
<p><strong>Geoffrey</strong> : I have only 7 episodes so far. Most are over an hour, but all are at least 45 minutes. I was going to work with other authors who would do an entire screencast, but it ended up being too difficult for now. So I’m doing more of a collaboration where I do the screencast, but someone else is the technical editor and helps with the content. The good part of that is that I learn as much as the people who buy the screencasts! I’ve learned a ton about JavaScript in the last few weeks, and I’m working with <a href="http://encytemedia.com"target="_blank" rel="noopener">Justin Palmer</a>.</p>
<p><strong>AkitaOnRails</strong> : Nice. PeepCode is only the name of the site? Is it a Topfunky related project? Or are both separated things?</p>
<p><strong>Geoffrey</strong> : Topfunky is my company, PeepCode is one of my products. The business is just my wife and I right now. I hope to keep it that way for as long as possible, but I might hire someone short-term in the next year.</p>
<h3>A Message to Brazil<span class="hx:absolute hx:-mt-20" id="a-message-to-brazil"></span>
    <a href="#a-message-to-brazil" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>AkitaOnRails</strong> : Ok, cool. Well, we could go on and on and on indefinitely (I’m loving this conversation). But I already have a lot of material here to work on. Anything else you want to talk about? Brazilian programmers, who are starting their careers, are very lost about what to do, what attitudes to have. What would be your words to them, as an experienced programmer and entrepreneur?</p>
<p><strong>Geoffrey</strong> : My advice is to <em>“stick it to the man.”</em> There are so many opportunities for developers. With the internet, everyone has a distribution channel. Many people think that a business isn’t worth starting unless you can sell it to Google for 4 billion dollars, but there are so many ideas out there that would be perfect to support a small business or a solo developer. Then you can use the income to fund your next billion-dollar idea. ;-)</p>
<p><strong>AkitaOnRails</strong> : yes, go on one step at a time. <a href="http://www.businessweek.com/magazine/content/06_33/b3997001.htm"target="_blank" rel="noopener">Kevin Rose</a> is a bad influence to all those youngsters :-)</p>
<p><strong>Geoffrey</strong> : Exactly. And you don’t even have to beat out the existing players in the market. There are many small niches that can support a person if the business idea is good.</p>
<p><a href="http://valleywag.com/tech/jason-fried/jason-fried-expands-his-little-thing-189142.php"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/next-small-thing-1.jpg" alt=""  loading="lazy" /></a></p>
<p><strong>AkitaOnRails</strong> : Jason Fried’s motto: <a href="http://www.37signals.com/svn/archives2/less_as_a_competitive_advantage_my_10_minutes_at_web_20.php"target="_blank" rel="noopener">underdoing instead of overdoing</a>.</p>
<p><strong>Geoffrey</strong> : Right. There are many businesspeople with great ideas, but they can’t implement them. As a developer, you have that skill, but you need the ideas. I’m not sure which one is more difficult!</p>
<p><strong>AkitaOnRails</strong> : Ok, Geoffrey, so it was such a pleasure to have this chance talking to you. I do hope I didn’t bore you because we have to continue this conversation in another occasion.</p>
<p><strong>Geoffrey</strong> : It was enjoyable, thanks! I’d love to come to Brazil sometime. I’ll be there if you host a Rails conference!</p>
<p><strong>AkitaOnRails</strong> : Ha! You bet, I’ll invite ya! I just need to find a sponsor :-)</p>
<p><strong>Geoffrey</strong> : Some of the best food I ever ate was at a Brazilian restaurant run by famous skateboarder Bob Burnquist.</p>
<p><strong>AkitaOnRails</strong> : There in Seattle?</p>
<p><strong>Geoffrey</strong> : No, in Los Angeles. The restaurant isn’t there anymore, unfortunately. Anyway, thanks for the interview! It was great to chat with you.</p>
]]></content:encoded><category>interviews</category><category>rails</category><category>open-source</category></item><item><title>Chatting with Dr. Nic</title><link>https://akitaonrails.github.io/en/2007/04/16/chatting-with-dr-nic/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/04/16/chatting-with-dr-nic/</guid><pubDate>Mon, 16 Apr 2007 13:01:00 -0300</pubDate><description>&lt;h3&gt;Chatting with Dr. Nic&lt;span class="hx:absolute hx:-mt-20" id="chatting-with-dr-nic"&gt;&lt;/span&gt;
&lt;a href="#chatting-with-dr-nic" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;img src="https://akitaonrails.s3.amazonaws.com/files/130749539_89959dd059.jpg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Today Carlos Eduardo, from &lt;a href="http://www.egenial.com.br"target="_blank" rel="noopener"&gt;e-Genial&lt;/a&gt;, proposed that I interview Dr. Nic Williams himself. The man of the hour. And I accepted right away and we started ‘skyping’ for a couple of hours. He is a nice guy and as educated and well informed as I expected. So, with no further ado, here it goes:&lt;/p&gt;
&lt;h4&gt;Who is Dr. Nic?&lt;span class="hx:absolute hx:-mt-20" id="who-is-dr-nic"&gt;&lt;/span&gt;
&lt;a href="#who-is-dr-nic" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;AkitaOnRails&lt;/strong&gt; : So, let’s start by telling our readers, who is Dr. Nic – I know, too generic, but let’s start from here :-)&lt;/p&gt;</description><content:encoded><![CDATA[<h3>Chatting with Dr. Nic<span class="hx:absolute hx:-mt-20" id="chatting-with-dr-nic"></span>
    <a href="#chatting-with-dr-nic" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://akitaonrails.s3.amazonaws.com/files/130749539_89959dd059.jpg" alt=""  loading="lazy" /></p>
<p>Today Carlos Eduardo, from <a href="http://www.egenial.com.br"target="_blank" rel="noopener">e-Genial</a>, proposed that I interview Dr. Nic Williams himself. The man of the hour. And I accepted right away and we started ‘skyping’ for a couple of hours. He is a nice guy and as educated and well informed as I expected. So, with no further ado, here it goes:</p>
<h4>Who is Dr. Nic?<span class="hx:absolute hx:-mt-20" id="who-is-dr-nic"></span>
    <a href="#who-is-dr-nic" class="subheading-anchor" aria-label="Permalink for this section"></a></h4><p><strong>AkitaOnRails</strong> : So, let’s start by telling our readers, who is Dr. Nic – I know, too generic, but let’s start from here :-)</p>
<p><strong>Dr Nic</strong> : I eat meat, am married, have a small boy, and I write software. In no specific order. I actually stopped writing software for a year or so – left my job and did other things. But everything I did had a software solution, so I found myself writing software for it. So, eventually, I learnt to love my inner nerd. Now I am happy :-)</p>
<p><strong>AkitaOnRails</strong> : So, let’s do a combo set of questions. Where are you from? What’s your current day job, is it Rails related? And what’s your history with Rails?</p>
<p><strong>Dr Nic</strong> : I am an Australian citizen, currently living in Sweden, working for a Swedish telephone company – Tele2 – for their billing project. It has nothing to do with Ruby. Two years ago I was in India, and was looking for a way to write code fast. I have a lot of ideas and it was taking a lot of effort to write them up in .NET. I saw <a href="http://www.rubyonrails.org/screencasts"target="_blank" rel="noopener">this video</a> on Ruby on Rails and my initial reaction was <em>“I hate all the &lt;% … %&gt; syntax”</em>. So I ignored it. I tried to make Ajax work with ASP.NET but it was so ugly and laborious at the time. I re-watched the Rails video and ignored the ugly brackets, and fell in love ever since. That’d be September 2005 I think</p>
<p><strong>AkitaOnRails</strong> : So, I think you have some serious concern about the brackets. What’s your position about them today, did you get used to them or tried something else?</p>
<p><strong>Dr Nic</strong> : No, I don’t mind them at all now. I don’t think I’ve ever tried an <a href="http://haml.hamptoncatlin.com/"target="_blank" rel="noopener">ERB replacement</a> in Rails. I use Textile/Redcloth for the newgem website. It was just one of those initial reaction things. I saw the &lt;% … %&gt; and that was what might have stopped me learning Ruby. Oh, I also remember thinking <em>“I don’t want to learn another language, how unnecessary”</em>. I’m glad I was wrong. Learning Ruby was necessary.</p>
<h4>Dr. Nic’s Magics<span class="hx:absolute hx:-mt-20" id="dr-nics-magics"></span>
    <a href="#dr-nics-magics" class="subheading-anchor" aria-label="Permalink for this section"></a></h4><p><strong>AkitaOnRails</strong> : I see that you like the ‘Magic’ side of the Ruby stuff. How did you come by with the <a href="http://magicmodels.rubyforge.org"target="_blank" rel="noopener">Magic Model</a> solution? I can guess that it felt quite natural, but what’s that story?</p>
<p><strong>Dr Nic</strong> : At Railsconf 2006, <a href="http://pragdave.pragprog.com/"target="_blank" rel="noopener">Dave Thomas</a> outlined a bunch of things he saw as <em>“things we can work on”</em> in Rails. One was lack of Composite Keys, another was the mysterious lack of DRYness in model files. I’d never released code to the Ruby community before (nor any community), but a few weeks later I just had these ideas for how to solve those two problems – both in the same week. I have no idea what possessed me to call the Magic Models that name. But I still like it. I just envisioned a magic show whereby you made the Model file disappear piece by piece yet it still worked. Thus the name. Ok, so I do know why I called it that. :-)</p>
<p><strong>AkitaOnRails</strong> : From a marketing stand point, I find it fantastic. You could call it something fancy as ‘Houdini’ but Magic Models does the job. I have a feeling that this is your most famous open source Rails project. Am I right or is there any other plugin of yours that is more compelling to the community right now?</p>
<p><strong>Dr Nic</strong> : I don’t think many people actually.. you know.. use the Magic Models. Deep down you need a model file as a placeholder for other functionality. So its more of a show-case of a concept. I have a 200 table schema that I use for a work. I use hooks to include additional stuff in the generated models. I hope that the <a href="http://newgem.rubyforge.org"target="_blank" rel="noopener">New Gem Generator</a> becomes popular. I’d like to see more people sharing code.</p>
<p><strong>AkitaOnRails</strong> : So, what can you tell us about the Gem Generator. What does it do? What is it all about?</p>
<p><strong>Dr Nic</strong> : Writing a gem from scratch isn’t simple/obvious. So ‘newgem’ creates a scaffolding for a gem, like the rails command creates a scaffolding for a rails app. It creates a folder containing a Rakefile, lib + test folders with some starter files, and a framework for managing a website on rubyforge.org. It uses the <a href="http://seattlerb.rubyforge.org/hoe/"target="_blank" rel="noopener">hoe</a> + rubyforge libraries as they are awesome. If people knew how good these two tools were they’d write more gems and less rails plugins.</p>
<p><strong>AkitaOnRails</strong> : Sounds pretty nice. It should make the deployment of new Gems a breeze. I am not very well aware of the RubyGems process and the RubyForge website. Have you tried to make some kind of partnership about the Gem Generator and the current Gem project? Maybe merging the two together to create a one-fits-all package?</p>
<p><strong>Dr Nic</strong> : When I first created it there was a bit of chat about it with the RubyGems guys, but I don’t think its important. ‘newgem’ is one gem scaffolding app; the hoe gem comes with ‘sow’ which creates a similar structure. And I think someone else is creating a gem scaffolding app. So the more the merrier. You see the same for rails. You have the ‘rails’ scaffolding, but now there are “mega-rails” apps, like <a href="http://hobocentral.net/"target="_blank" rel="noopener">Hobo</a>, that give you so much more of a headstart in creating an app. I start gems/projects because I need the solution and I think other people will want it too. If someone makes a better version, that’s great. I can stop supporting my version :-)</p>
<p><strong>AkitaOnRails</strong> : Yes, and Streamlined and AjaxScaffold. I was hoping to see both of them releasing new versions sooner. They <a href="http://www.height1percent.com/articles/2006/08/17/ajaxscaffold-and-streamlined-developers-to-collaborate"target="_blank" rel="noopener">announced a merging collaboration</a> but I never heard from them again. Have you?</p>
<p><strong>Dr Nic</strong> : <a href="http://www.akitaonrails.com/2006/12/01/come%C3%A7ando-com-o-plugin-ajax-scaffold"target="_blank" rel="noopener">AjaxScaffold</a> became a plugin and has now been rebranded as <a href="http://activescaffold.com/"target="_blank" rel="noopener">ActiveScaffold</a>. Its still under active development by <a href="http://www.height1percent.com/"target="_blank" rel="noopener">Richard White</a> + others. Actually, AjaxScaffold was the first project I ever helped with, before I wrote <a href="http://compositekeys.rubyforge.org/"target="_blank" rel="noopener">CPK</a> + <a href="http://magicmodels.rubyforge.org/"target="_blank" rel="noopener">Magic Models</a>. So I learnt a lot about gems and rails generators from its code. I’ve never used <a href="http://www.streamlinedframework.org/"target="_blank" rel="noopener">Streamlined</a> but its still under active development as far as I know. I’m not a fan of open source projects merging. Often they are built around the inspiration of an individual. Those individuals mightn’t share nicely together :-) Plus, its a whole bunch of work to merge two blocks of code.</p>
<h4>Open Sourcing<span class="hx:absolute hx:-mt-20" id="open-sourcing"></span>
    <a href="#open-sourcing" class="subheading-anchor" aria-label="Permalink for this section"></a></h4><p><strong>AkitaOnRails</strong> : Going back to your previous statement: don’t abandon your project. Fight for it! :-) But talking seriously, development and support require a lot of effort. Mainly with support, bug fixes and all. Do you get a lot of help from the community, maybe patches?</p>
<p><strong>Dr Nic</strong> : Help + patches – that has turned out to be the best thing about open source (OSS) – people fix your code, or at the very least ask <em>“why didn’t you do it [an alternate] way?”</em></p>
<p><strong>AkitaOnRails</strong> : Hm, let me digress a little bit. I have mixed feelings about merging and forking. I usually don’t like forking unless the original team have gone numb like what happened to the <a href="http://pt.wikipedia.org/wiki/Fork"target="_blank" rel="noopener">XFree86</a> project. Alternatives should really be very different like KDE and Gnome, and they are fine. But components that do most of the same things or complement each other like the current <a href="http://lwn.net/Articles/229690/"target="_blank" rel="noopener">beryl and compiz</a> discussion, maybe it’s ok for them to merge and focus effort on a single direction. What do you think? For instance, I think that a multi connection support like yours or Rev.Health’s one should be in the main Rails tree. It’s as important as the database adapters. Or maybe not?</p>
<p><strong>Dr Nic</strong> : There is a project <a href="http://drysql.rubyforge.org/"target="_blank" rel="noopener">DRYSql</a> that is for all intents and purposes similar to the Magic Models. It’s not a fork, but the code would be similar. But I’m glad he did it. I think OSS is driven by inspiration – and people like to have their name attached to code. If he writes more code because it has his name on it, then that’s great. Regarding more vs. less in Rails – I think more code should be extracted from Rails, rather than more code added to Rails. Unfortunately if you take things out, then the anti-rails movement say stupid things like <em>“Oh rails can’t do XXX”</em> even if there is a plugin/gem that can do it, or even if you could do it in 5-100 lines of purpose built code. But we’re not here to make the anti-railers happy, just ourselves. So, extract code out of rails-core and set it free.</p>
<p><strong>AkitaOnRails</strong> : Yes, like the current desire to cut out the Active Web Services support as it seems like fewer people are using it, and make it into a plugin. That’s right, the more it is in the core, the heavier it gets to load the process.</p>
<p><strong>Dr Nic</strong> : Let people choose prototype/scriptaculous vs. jquery for example. But, no one will do that – not worth the effort. And right – no need for AWS anymore – its already packaged as a separate gem. You just stop making it a dependency in the rails gem. So that’s an easy one. But my attitude is that Rails is perfect given that it’s only a few years old, completely Open Source, and has a wonderful community of intelligent, caring developers who can <em>“scratch their own itches”</em> and then share the results via blogs + forums.</p>
<p><strong>AkitaOnRails</strong> : I am personally a little bit worried about this because Rails is becoming something as the Linux kernel. Linux doesn’t have a specific set of <a href="http://www.kroah.com/log/linux/ols_2006_keynote.html"target="_blank" rel="noopener">stable APIs</a>, so each new version has to tweak some of its drivers. It works because all of the drivers’ source code are in the main tree. Rails is like the same: I asked DHH (refer to my book’s interview) about stable APIs and he is not very fond of limiting what he wants by providing stable APIs through out newer versions. So plugins are destined to fail someday unless they are delivered along side the main distribution. Maybe we’re going to see <em>‘Rails Distros’</em> in long run?</p>
<p><strong>Dr Nic</strong> : Fragmented rails – yep that’s a valid concern. I think you will see “rails distros”. I think they already exist. But they aren’t called that. <a href="http://hobocentral.net/"target="_blank" rel="noopener">Hobo</a> for example could be a rails distro. So one day we could have a HoboConf.</p>
<p><strong>AkitaOnRails</strong> : Actually I just got into this <em>Distros</em> conclusion. Maybe I should start assembling my own :-) The <em>Akita Rails Distro</em>.</p>
<p><strong>Dr Nic</strong> : Just make sure you do screencasts. They sell software. Having given that pearl of wisdom, I’m not sure why I don’t do them. Writing blog articles is fun and time consuming, that’s probably why. But videos work. Rails success will be noted in the history books, in part, to <a href="http://rubyonrails.org/screencasts"target="_blank" rel="noopener">that 15 min video</a>.</p>
<h4>Twitter vs. DHH – Round 2<span class="hx:absolute hx:-mt-20" id="twitter-vs-dhh--round-2"></span>
    <a href="#twitter-vs-dhh--round-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h4><p><strong>AkitaOnRails</strong> : Speaking of which, support, plugins, I have to ask you something delicate (<em>I don’t want it to become an excuse for another flame-war</em>): what do you think about the current <a href="http://www.akitaonrails.com/2007/04/15/a-polemica-twitter"target="_blank" rel="noopener">Twitter vs DHH</a> discussion? Twitter says: <em>Rails should have given us the solution</em>. DHH says: <em>Twitter could have contributed back with a solution</em>. I think this kind of argument doesn’t do any good for the community, as I <a href="http://www.akitaonrails.com/2007/04/15/a-polemica-twitter"target="_blank" rel="noopener">posted</a> at my blog yesterday. What are your insights about it?</p>
<p><strong>Dr Nic</strong> : The guys at Twitter have already contributed code to Ruby community (<a href="http://romeda.org/blog/2006/11/announcing-jabbersimple.html"target="_blank" rel="noopener">Jabber API</a>), and when they settle on a solution for their situation, I think they will be very happy to share it with us. That will be great. Remember: Rails is 2 years old. .NET + ISS is 7+ years old. Java is 10 years old. LAMP is very old. So, its all in front of us. Exciting times.</p>
<p><strong>AkitaOnRails</strong> : And you didn’t <a href="http://www.loudthinking.com/arc/000610.html#comments"target="_blank" rel="noopener">get your t-shirt</a>, or did you? :-)</p>
<p><strong>Dr Nic</strong> : No one has asked my address – a query that preludes the sending of t-shirts.</p>
<p><strong>AkitaOnRails</strong> : hahaha, and did you get feedback from the community about the magic multi connection (MMC) and the Twitter discussion? By the way, how did you come by the global array of connection modules solution?</p>
<p><strong>Dr Nic</strong> : I think the most important aspect of the MMC is that it answers the doubts of whether Rails CAN connect to multiple databases. It is a silly thing to say <em>“Rails cannot connect to multiple databases”</em> but the anti-railers like the way it sounds, I think. Even without the MMC, you can create your own connection pool, and manually assign the connections before each request. The MMC hides this via modules. Revolution Health’s solution moves the allocation of connections into the CRUD methods. All the same solution. Just different levels of control and different syntax.</p>
<p><strong>AkitaOnRails</strong> : But did you think about that before, or was the heat of the discussion what motivated you to hack together a solution?</p>
<p><strong>Dr Nic</strong> : I’d written the gem a week earlier to scratch an itch. The idea of using modules to control ActiveRecord model behaviour appeals to me from a “magic” sense. Its cute. For example, the latest Magic Models allows you to use Modules to specify table name prefixes. So, I had the gem, and Twitters issue turned up. So I wrote the blog article and the tutorial as a result. I was going to release the gem in a few days but not aimed at the master-slave issue. It was built with the aim of using it for admin websites that need to connect to 2+ different databases. I’ll blog about that later.</p>
<p><strong>AkitaOnRails</strong> : Really excellent timing. Did you hear something from the Twitter guys? Now someone has to build a screencast explaining Railers how to set up a master-slave replication between MySQL databases first :-)</p>
<p><strong>Dr Nic</strong> : I think more Railers are interested in how they get their Rails app into production in the first place :-) They dream of having scaling issues. <em>“Oh, my Google Ad-sense account is full. What should I do with all that money.”</em></p>
<h4>Community and Macs!<span class="hx:absolute hx:-mt-20" id="community-and-macs"></span>
    <a href="#community-and-macs" class="subheading-anchor" aria-label="Permalink for this section"></a></h4><p><strong>AkitaOnRails</strong> : Speaking of the community, do you attend to a lot of conferences, events? Have you been in the latest RailsConf EU? What are your opinion about what’s going on around the community?</p>
<p><strong>Dr Nic</strong> : I met only a handful of people at the Railsconf 2006. I sat in the audience watching all the famous Rails bloggers speak, like everyone else in the audience. I felt very happy to be there. I was one of 50 people with a PC laptop. I did a lightning presentation on RadRails vs TextMate for a few laughs. Travelling from Europe to Chicago cost a bit of money, so even though RailsConf EU was across the channel in London it was vetoed by the Williams financial panel. But I’m off to RailsConf again in May, should be wonderful. The community of Rubists is awesome.</p>
<p><strong>AkitaOnRails</strong> : (<em>I wish I could be there as well – sigh</em>) well, so it means your primary machine is Windows based. Are you still using RadRals or have you tried the newest contenders like “E” or even the NetBeans and IntelliJ’s Ruby integration?</p>
<p><strong>Dr Nic</strong> : Ahh, it <em>was</em> a PC. I bought a unix laptop, with an Apple logo :-) The PC was old and making a lot of whirring noises. I just couldn’t find a reason to stay with the PC vs. the possibilities with OSX. I’m not an Apple Fanboy, but I love my Mac.</p>
<p><strong>AkitaOnRails</strong> : Let me guess: Macbook Pro 15&quot; Core 2 Duo 2.33?</p>
<p><strong>Dr Nic</strong> : Macbook 13&quot; – I use it on the bus and train.</p>
<p><strong>AkitaOnRails</strong> : Haha, I also say that: <em>“I’m not an Apple Fanboy”</em>. Maybe someone should create the category of <em>“the Deniers”</em> :-)</p>
<p><strong>Dr Nic</strong> : I love my wife, my son and my mac, officially, in that order.</p>
<p><strong>AkitaOnRails</strong> : I wish I could use mine at the train, but I would be robbed in less than 10 seconds. No doubt about that.</p>
<p><strong>Dr Nic</strong> : Ha. Its a big planet. You could move.</p>
<h4>Dr. Nic’s Career Advice<span class="hx:absolute hx:-mt-20" id="dr-nics-career-advice"></span>
    <a href="#dr-nics-career-advice" class="subheading-anchor" aria-label="Permalink for this section"></a></h4><p><strong>AkitaOnRails</strong> : Nice proposition. I am thinking about it. By the way. At the beginning of this conversation you told us that you’ve been working in India? How come? Any kind of consultancy work for any of the major companies like Tata, Wipro, Satyam? What are your opinions about the recent discussions and worries, like the Chad Fowler’s book <a href="http://www.rubyonbr.org/articles/2006/10/18/por-que-aprender-ruby-o-torna-um-programador-pior-por-akita/"target="_blank" rel="noopener">My Job web to India</a>?</p>
<p><strong>Dr Nic</strong> : I went to India for the same project I’m on now with the Swedish company. Back then it was for Accenture, who were doing the work at the time out of India. I have a copy of Chad’s e-book… damn, haven’t read it yet. But thanks for the reminder. I have lots of thoughts about <em>“outsourcing to India”</em>. But they aren’t positive, so I’ll take a pass. They are more the topic of conversation when alcohol is involved. :-)</p>
<p><strong>AkitaOnRails</strong> : haha, if you ever think about doing outsourcing services, consider Brazil. Did you hear anything about us in outsourcing conversations?</p>
<p><strong>Dr Nic</strong> : Never. People who I hear talking about outsourcing mention “India”, several asian countries, and eastern european countries. Never Brazil.</p>
<p><strong>AkitaOnRails</strong> : Damn, I knew it :-)</p>
<p><strong>Dr Nic</strong> : So, just pretend you are American and ask for American rates.</p>
<p><strong>AkitaOnRails</strong> : Good advice. I just <a href="http://www.akitaonrails.com/en/2007/04/14/off-topic-seja-arrogante"target="_blank" rel="noopener">wrote an article</a> about the importance of being fluent in english at my blog. That’s one compelling reason.</p>
<p><strong>Dr Nic</strong> : Absolutely. Clients don’t pay per line of code. They kind of pay for results, and kind of pay for working with people they like and trust. I think.</p>
<p><strong>AkitaOnRails</strong> : And I agree with that statement: people hire competency, in general. And have you ever considered flying down on vacation to Brazil?</p>
<p><strong>Dr Nic</strong> : Absolutely, its on our list of places to visit.</p>
<p><strong>AkitaOnRails</strong> : And what do you know or hear about our humble home country? (<em>default question to a foreigner, I had to ask.</em>)</p>
<p><strong>Dr Nic</strong> : Football, poverty, women, the big statue on the hill, and the Amazon.</p>
<p><strong>AkitaOnRails</strong> : I bet it’s better than New Delhi or Bangalore.</p>
<p><strong>Dr Nic</strong> : They have poverty, but no statue on a hill :-)</p>
<p><strong>AkitaOnRails</strong> : Well, I guess I already took a lot of your time. What about calling it a day? Do you have anything you want to say to the brazilian audience? Career Recommendations? :-)</p>
<p><strong>Dr Nic</strong> : Career advice… Learn English, be proud of being Brazillian, and enjoy writing code.</p>
<p><strong>AkitaOnRails</strong> : ow, last question! Is <em>Nic</em> short for <em>Nicholas</em>? Dr. Nicholas Williams?</p>
<p><strong>Dr Nic</strong> : Correct. PhD in Computer Science. I just use the <em>Dr Nic</em> name ‘cause it’s a bit different. I don’t mean to show off the “Dr” part.</p>
<p><strong>AkitaOnRails</strong> : Very nice! Dr. Nic, then :-) Very glad for this opportunity. I look forward to more conversations like this. Too bad we can’t do it in a bar with beers.</p>
]]></content:encoded><category>interviews</category><category>rails</category><category>open-source</category></item><item><title>Off Topic: A Rant</title><link>https://akitaonrails.github.io/en/2007/03/14/off-topic-um-desabafo/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2007/03/14/off-topic-um-desabafo/</guid><pubDate>Wed, 14 Mar 2007 03:02:00 -0300</pubDate><description>&lt;p&gt;Fair warning: this post is going to get a bit &amp;ldquo;philosophical&amp;rdquo; again. I don&amp;rsquo;t have the resources for a rigorous approach, with field research and statistical analysis of a huge sample. All I have is my own practical experience and whatever data is publicly available.&lt;/p&gt;
&lt;p&gt;One such data point is this survey: &lt;a href="http://web.archive.org/web/20080827190222/http://idgnow.uol.com.br/carreira/2006/08/21/idgnoticia.2006-08-21.7048942010"target="_blank" rel="noopener"&gt;Survey says 75% of IT professionals want to change jobs&lt;/a&gt;. It&amp;rsquo;s old, from the middle of last year, but I see it in practice. A few days ago some friends came to me with exactly this: &lt;em&gt;&amp;ldquo;I&amp;rsquo;m unhappy with what I&amp;rsquo;m doing.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>Fair warning: this post is going to get a bit &ldquo;philosophical&rdquo; again. I don&rsquo;t have the resources for a rigorous approach, with field research and statistical analysis of a huge sample. All I have is my own practical experience and whatever data is publicly available.</p>
<p>One such data point is this survey: <a href="http://web.archive.org/web/20080827190222/http://idgnow.uol.com.br/carreira/2006/08/21/idgnoticia.2006-08-21.7048942010"target="_blank" rel="noopener">Survey says 75% of IT professionals want to change jobs</a>. It&rsquo;s old, from the middle of last year, but I see it in practice. A few days ago some friends came to me with exactly this: <em>&ldquo;I&rsquo;m unhappy with what I&rsquo;m doing.&rdquo;</em></p>
<p>These articles need to be taken with a grain of salt, since most of them report on the American market. This other one, for instance, says <a href="http://web.archive.org/web/20100926130559/http://idgnow.uol.com.br:80/carreira/2006/08/15/idgnoticia.2006-08-15.9911074683/IDGNoticia_view/"target="_blank" rel="noopener">programmers are the highest paid in tech</a>. In Brazil that&rsquo;s not necessarily true. Here the programmer earns &ldquo;enough,&rdquo; and the bigger paychecks go to analysts (people with degrees in all sorts of fields who use technology as a work tool). And it&rsquo;s precisely those analysts and consultants, some making up to R$100,000 a year, who complain the most about their own salaries.</p>
<p><a href="http://en.wikipedia.org/wiki/Von_Neumann"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/neumannface_en.jpg" alt=""  loading="lazy" /></a></p>
<p>Another complaint I hear all the time: <em>&ldquo;I&rsquo;m not enjoying where I work anymore because it doesn&rsquo;t &lsquo;add&rsquo; anything to me. I want to move to other projects to learn more.&rdquo;</em> Wanting to change is admirable, but I believe most people are aiming at the wrong target. A colleague of ours put it well: <em>&ldquo;the vast majority of projects are all the same: data entry screens and more data entry screens.&rdquo;</em> That&rsquo;s exactly it. It&rsquo;s the descendant of the old field called <em>Data Processing</em>, which people now call <em>Information Systems</em>.</p>
<p>There should be more than that. Outside of programming you have Business Intelligence, Customer Relationship Management, Supply Chain, and several other cutting-edge areas, the ones that set apart the companies that already control the basics: accounting, sales, purchasing, manufacturing, maintenance, quality control.</p>
<p>In Brazil, the vast majority of &ldquo;programmers&rdquo; customize processes that already exist. One department wants to automate employee records: it buys or builds its own forms. Another wants a sales form that feeds the sales system and notifies an external partner to update inventory. Another needs screens to control a customer service workflow. Forms and more forms, always some variation of a form.</p>
<p><a href="http://en.wikipedia.org/wiki/Konrad_Zuse"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/zuse.jpg" alt=""  loading="lazy" /></a></p>
<p>No wonder so many programmers are dissatisfied. Usually they can&rsquo;t say why, but they feel something is wrong. And please, <em>don&rsquo;t take anything here literally</em>. There are dozens of fascinating projects out there, with complex algorithms for medical technology, aerospace, engineering. I&rsquo;m talking about the majority, not everyone.</p>
<p>This cycle of data entry is old. Since COBOL, since the 70s, data processing brought dynamism to the modern world, eliminating tons of paper and legions of bureaucrats whose only job was to fill out and control that paper. And it will never end, unless computers get smart enough to stop needing &ldquo;mere&rdquo; programmers. You never know.</p>
<p>Meanwhile, the market will keep needing &ldquo;data entry programmers.&rdquo; It doesn&rsquo;t matter whether you use Struts, Spring, Rails, or Symfony: you&rsquo;ll be building user records, client records, material records, content records, complaint records, contract records, address records, vendor records. The list is enormous. Especially where &ldquo;modernization&rdquo; hasn&rsquo;t arrived yet, where bureaucrats abound and processes haven&rsquo;t even been stabilized, let alone automated.</p>
<p>I started out building data entry screens in the late 80s, with dBase and Clipper. Most of the client-server era (2-tier) was exactly that: a database on the server and entry screens on the client. When the Web arrived, seductive applications showed up, search engines and webmail, and suddenly everyone wanted to build a website. Whoever invented TCP/IP, HTTP, HTML, SMTP, POP3 must have had a blast. For the rest of us, what was left was more data entry. An email screen is a form. An e-commerce screen is a form. Companies swapped their Visual Basic screens for browsers: data entry dressed up as web pages.</p>
<p><a href="http://en.wikipedia.org/wiki/Grace_Hopper"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/hoppergrace_big.jpg" alt=""  loading="lazy" /></a></p>
<p>It&rsquo;s no coincidence that so many frameworks keep popping up: Struts, Velocity, Lucene, Jackrabbit, Spring, Guice. A real programmer loves the plumbing. We like understanding how this mesh of code works, how to optimize it, how to make it stable, how to wire things together. Plenty of people in Brazil think this way, but far fewer than in the United States. We have nothing even close to a repository like Apache Jakarta. Brazilians contribute to various open source projects, but it&rsquo;s a small fraction.</p>
<p>I can see it in the Rails case. Rails appeared recently, and it didn&rsquo;t come out of the US. Even so, it spread fast over there. Here, aside from small communities like the competent RubyOnbr, we have nothing: nothing interesting in the media, nothing interesting at conferences (which are few to begin with). Nothing, zip, nada.</p>
<p>My book, &ldquo;Repensando a Web com Rails,&rdquo; barely sold its first print run of 1,000 copies. The excellent &ldquo;Agile Web Development with Rails&rdquo; sold tens of thousands abroad. Setting aside which book is &ldquo;better&rdquo; or &ldquo;worse,&rdquo; the meteoric sales, the dozens of other titles launched there, and the fact that mine is still the only one here are a thermometer of the cultural difference, in the market and among programmers alike.</p>
<p>Fair enough: we went through a dark period of closed markets and years of lag. But today I see no reason for programmers, especially the younger ones, to be so apathetic about technology.</p>
<p><a href="http://en.wikipedia.org/wiki/Herman_Hollerith"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/Herman-Hollerith.gif" alt=""  loading="lazy" /></a></p>
<p>At times like this I miss the late 80s (that&rsquo;s the era I lived; older folks will feel the same about the late 70s). We were very few, and running into a programmer or even an enthusiast was rare. But we thought differently.</p>
<p>Even in the mid-90s, just before the internet boom, my friends and colleagues were all in love with technology. We talked about what was new, what each of us had learned, what we were testing. We traded ideas, argued techniques, and the goal was always to learn more. I knew people whose hobby was writing little animations in Assembly. Others bought electronic components to build their own MP3 player (iPods didn&rsquo;t exist yet). Some spent hours building tools for this thing called the &ldquo;internet&rdquo; that was still new to us. Those were good times.</p>
<p>Then the Brazilian IT market exploded, for all sorts of reasons. Suddenly a lot of people saw the field as a quick way to make money. Suddenly universities were packed with kids learning tools instead of technology, graduating as information systems technicians where computer science graduates used to come out. Suddenly everyone &ldquo;knew&rdquo; Java. And finally the market was saturated with &ldquo;programmers.&rdquo;</p>
<p>Now all I hear from today&rsquo;s &ldquo;programmers&rdquo; is <em>&ldquo;which language do you think I should learn that will make the most money?&rdquo;</em> You can imagine how frustrating that is for someone who already feels like part of the <em>old guard</em>. I never thought about the cost-benefit of learning time. I always took learning as a constant; if I made money along the way, great, but that was never the point.</p>
<p><a href="http://en.wikipedia.org/wiki/Marvin_Minsky"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/150px-Marvin_Minsky.jpg" alt=""  loading="lazy" /></a></p>
<p>Because of the current state of absurdity in the market, I witness things that scare me. At one client, they &ldquo;integrated&rdquo; the sales system with the activation system for a piece of equipment. The logic is simple: once the sale goes through, the customer&rsquo;s equipment should be activated. Even without a two-phase commit solution (everyone knows what atomic transactions are, right?), the requirement called for safeguards to guarantee that.</p>
<p>Obviously there were no safeguards at all, and nobody ever asked: not the programmers, not the analysts, and certainly not the managers. The result: today several people are employed whose only job is formatting spreadsheets full of errors and fixing them by hand. More data entry screens were built to handle those errors. Did the project deliver automation gains? Sure, but far less than it should have. And nobody cares. I&rsquo;ve seen worse.</p>
<p>It saddens me to see how little knowledge the bulk of programmers and the whole chain above them (programmers turned analysts, programmers turned managers) actually have, and how poor the architectures and solutions they produce are as a consequence.</p>
<p>Back to the questions people asked me: the unhappiness with what they do, the feeling of not living up to their &ldquo;potential,&rdquo; the urge to learn something new to earn more money. I have no answers for that because I can&rsquo;t think that way. More than that: I believe those questions are fundamentally wrong. And a wrong question has no right answer.</p>
<p>I try to spread the culture I knew as a young programmer: learning. The excuses I hear are always the same: <em>&ldquo;I don&rsquo;t have time to learn when I have to work to support myself&rdquo;</em>, <em>&ldquo;I can&rsquo;t read English, so I need courses and can only learn one thing at a time&rdquo;</em>, <em>&ldquo;no point learning this &lsquo;X&rsquo; thing because I don&rsquo;t know if I&rsquo;ll use it at work&rdquo;</em>, <em>&ldquo;I&rsquo;m stressed enough at work; in my free time I just want to rest.&rdquo;</em> And so on. A long list of excuses.</p>
<p>It&rsquo;s human nature to resist leaving your comfort zone and, worse, to complain when you become obsolete. <em>&ldquo;It&rsquo;s the government&rsquo;s fault&rdquo;</em>, <em>&ldquo;it&rsquo;s capitalism&rsquo;s fault&rdquo;</em>, <em>&ldquo;it&rsquo;s my boss&rsquo;s fault.&rdquo;</em> More excuses.</p>
<p><a href="http://en.wikipedia.org/wiki/Alan_Turing"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/turing.jpg" alt=""  loading="lazy" /></a></p>
<p>When I wrote my book, I did it for two reasons: to learn something new and to help others learn along. <strong>Learning</strong> and <strong>Teaching</strong> are the two fundamental motivators of every good programmer. I understand that in Brazilian reality, ignoring money is not an option. I found a balance between the two, and I don&rsquo;t see why nobody else could. Standing still, sitting on the little you learned years ago, complaining nonstop, never got anyone anywhere.</p>
<p>If it&rsquo;s worth anything, here are some personal suggestions:</p>
<ul>
<li>
<p>The more you learn, the better your solutions. Clients recognize a professional who knows what they&rsquo;re talking about, and everyone can tell when someone is just bluffing.</p>
</li>
<li>
<p>The demands that will grow the most are systems integration and analyzing large amounts of data. The only way to deal with that is knowing dozens of concepts and technologies. Learning one tool in a course won&rsquo;t help.</p>
</li>
<li>
<p>The technology cycle keeps getting shorter. A new version used to take years; now it takes months. By the time you finish the course, what you learned is already obsolete. Deal with it. Get ahead. Learn as much as you can before the technology is even available.</p>
</li>
<li>
<p>Jumping from job to job doesn&rsquo;t solve it. A new project won&rsquo;t necessarily bring anything new (the odds of it being just another data entry screen are high). And leaving it to learn only when you already need to, inside the project, is too late: you&rsquo;ll be overtaken by people who know what you should already know. A good programmer learns ahead of need. Once a poor-quality product hits production, the result is bad for the client and for your reputation.</p>
</li>
<li>
<p>Try to innovate inside your own project. I&rsquo;m not telling anyone to risk a project by bringing in things so new they could blow up the next day. There&rsquo;s always a better way to do what you&rsquo;re doing without touching the schedule or the cost. Learning to be efficient with quality is part of a programmer&rsquo;s job, and it takes a lot of practice.</p>
</li>
<li>
<p>Think you&rsquo;re a good programmer but underused? Then put yourself to better use: create or join open source projects. That&rsquo;s one of the qualities of open code: you get to use for free what others built, learn from a solid base, and still have the chance to give back.</p>
</li>
<li>
<p>Stop complaining. Complaining builds a negative mindset, annoys everyone around you, and leads to no solution at all. A complaint is one more excuse, noise that hides the real problem. And the real problem is this: you complain about the job, the project, the boss, but the person you really want to complain about is yourself. Complaining is the externalization of the frustration of being who you are and failing to become more. And that is not a physical incapacity: it&rsquo;s mental laziness.</p>
</li>
<li>
<p>Forget courses and translated books: they&rsquo;re always outdated. In the 80s we had no certifications or games of that sort. We slept with an algorithms book on the nightstand and woke up to a new language spec over breakfast.</p>
</li>
</ul>
<p><a href="http://en.wikipedia.org/wiki/Charles_Babbage"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/files/charles-babbage.jpg" alt=""  loading="lazy" /></a></p>
<p>Good cooks appreciate good food on vacation. Good engineers analyze their own car on a road trip. Good artists sketch new ideas on a restaurant napkin. Good professionals <strong>LOVE</strong> what they do, and not only at work. Loving it here means appreciating, respecting, and wanting to learn more about the profession, which is very different from taking work home. Da Vinci didn&rsquo;t need courses. Mozart didn&rsquo;t need courses. A course only helps someone who is already on track and knows exactly what they want out of it.</p>
<p>When I buy my iPod I want to know how it&rsquo;s made (did you know it uses a hard drive with perpendicular bit recording, which increases data density?). When a spam filter blocks something, I want to know how it works (did you know some of the most efficient ones are based on Bayesian statistical algorithms?). When I install an operating system, I need to know exactly how it works (did you know your new hardware supports DEP protection, but it&rsquo;s probably disabled on your Windows? By the way, has anyone stopped to find out what DEP is?). When I use someone else&rsquo;s network, I want to be sure nobody will spy on what I&rsquo;m doing (have you ever used an external SSH server to create dynamic tunnels?). When I buy a new TV, I want to get the most out of it (has anyone here bought a plasma TV and hooked an antenna up to it? Or worse: plugged the DVD player in with a composite cable and can&rsquo;t figure out why the picture is so bad?).</p>
<p>And these things aren&rsquo;t just bar-talk curiosities. I read a lot, nearly 100 feeds on the most diverse subjects. Over 100 posts an hour, every day. Plus dozens of podcasts and a bunch of books, printed or PDF. And I still think it&rsquo;s not enough. A certification whose only merit is one more line on your resume is the same as nothing. I still stand by the principle that professionals who genuinely love what they do (and show it by learning more and more) will never be out of a job. The ones who start from the goal of making money, ironically, will have the hardest time getting it.</p>
]]></content:encoded><category>career</category><category>learning</category><category>open-source</category><category>off-topic</category></item></channel></rss>