<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Javier Leandro Arancibia</title>
    <description>The latest articles on DEV Community by Javier Leandro Arancibia (@javimosch).</description>
    <link>https://dev.to/javimosch</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1655837%2F30baec18-fb3d-4a4b-97af-0441d12b5f28.jpg</url>
      <title>DEV Community: Javier Leandro Arancibia</title>
      <link>https://dev.to/javimosch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/javimosch"/>
    <language>en</language>
    <item>
      <title>machin v0.140.0: scoping X-Forwarded-For trust to the proxy</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 25 Sep 2026 06:40:08 +0000</pubDate>
      <link>https://dev.to/javimosch/machin-v01400-scoping-x-forwarded-for-trust-to-the-proxy-4bll</link>
      <guid>https://dev.to/javimosch/machin-v01400-scoping-x-forwarded-for-trust-to-the-proxy-4bll</guid>
      <description>&lt;p&gt;v0.140.0 is a small release — one file, 37 lines added — but one of the two changes is the kind of thing that bites you only when it matters, so it's worth a few words.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;serve_on, and trust X-Forwarded-For only from the proxy (#671)&lt;/strong&gt; — the machweb framework now scopes trust of the &lt;code&gt;X-Forwarded-For&lt;/code&gt; header to requests that arrive through the configured proxy. &lt;code&gt;serve_on&lt;/code&gt; is the new entry point that wires this up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;map_free: reclaim a transient map on the main goroutine's arena (#667 / #669)&lt;/strong&gt; — a transient map allocated on the main goroutine's arena is now explicitly freed instead of lingering until the arena is torn down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v0.140.0&lt;/strong&gt; — the version bump that carries the above.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;X-Forwarded-For&lt;/code&gt; change is the interesting one. The header exists so a reverse proxy can tell your app the real client IP when it terminates the connection. The problem is that the header is just text — any client can send it. If your app trusts &lt;code&gt;X-Forwarded-For&lt;/code&gt; unconditionally, a request that never went through your proxy can still claim to be from any IP it likes. That defeats IP-based rate limiting, geo checks, allow/deny lists, and audit logs.&lt;/p&gt;

&lt;p&gt;The fix is to trust the header only on requests you know came from your proxy — typically by checking the peer address against the proxy's address. That's what this change does. It's a small, unglamorous guard, but it's the difference between "the proxy tells me the client IP" and "anyone tells me the client IP."&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;map_free&lt;/code&gt; change is a memory hygiene fix in the same vein: an arena allocator is a great fit for a request's lifetime, but a transient map that outlives its usefulness still holds a slot until the arena resets. Reclaiming it explicitly keeps peak memory from ratcheting up on long-lived arenas.&lt;/p&gt;

&lt;p&gt;Neither change is flashy. Both are the kind of thing you only notice when you're debugging a spoofed-IP incident or a slow memory climb — at which point you wish you'd done them earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;https://github.com/javimosch/machin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>testing</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A 7M-parameter model that knows when to say no</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Thu, 24 Sep 2026 05:16:56 +0000</pubDate>
      <link>https://dev.to/javimosch/a-7m-parameter-model-that-knows-when-to-say-no-4phn</link>
      <guid>https://dev.to/javimosch/a-7m-parameter-model-that-knows-when-to-say-no-4phn</guid>
      <description>&lt;p&gt;Most requests sent to an LLM are boring. "What's the weather in Osaka", "remind me to call mom", "what's 47 times 23". A frontier model answers them beautifully — and every call costs real money and a network round-trip.&lt;/p&gt;

&lt;p&gt;I built the opposite end of that trade-off: &lt;strong&gt;a 7.2M-parameter dispatcher that only does triage&lt;/strong&gt;. It reads a request, picks a typed route, reports calibrated confidence — and when it isn't sure, it says so and hands off instead of guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  One call, one typed decision
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;/route&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remind me to call mom tomorrow at 6pm"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tool_call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"route"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"set_reminder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"call"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"set_reminder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.9999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"latency_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;/route&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"write me a 2000-word essay on the roman empire"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"delegate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"route_escalate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.96&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gates are explicit: low confidence → delegate. Escalation head fires → delegate. Decision head and generative trunk disagree → delegate. A dispatcher that guesses wrong confidently is worse than no dispatcher.&lt;/p&gt;

&lt;h2&gt;
  
  
  The unusual part: zero ML framework
&lt;/h2&gt;

&lt;p&gt;Tokenizer training, pretraining (AdamW/RoPE/RMSNorm/SwiGLU), fine-tuning, int8 export, and the OpenAI-compatible CPU server are all written in &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;machin/MFL&lt;/a&gt; — a language designed to be &lt;em&gt;written by machines&lt;/em&gt;. No PyTorch, no ONNX, no llama.cpp.&lt;/p&gt;

&lt;p&gt;The shipped artifact is a static binary + an 8MB int8 model. The whole appliance tarball is &lt;strong&gt;7.5MB&lt;/strong&gt; — untar, &lt;code&gt;./start.sh&lt;/code&gt;, and you have typed decisions on &lt;code&gt;:8097&lt;/code&gt; in ~15ms per call on a laptop CPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  Per-customer routing without fine-tunes
&lt;/h2&gt;

&lt;p&gt;Decisions come from tiny linear heads (~7KB artifacts) trained on the frozen trunk's hidden state. A customer's routes are a config file of example phrases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"routes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"reset_password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"reset my password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"locked out"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"escalate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"migrate our infrastructure"&lt;/span&gt;&lt;span class="p"&gt;]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;head_studio.py&lt;/code&gt; validates it, synthesizes train/eval data, trains the head, reports accuracy + ECE + confusion. Multi-tenant serving swaps heads per API key — same trunk, different router per customer.&lt;/p&gt;

&lt;p&gt;There's a runnable proof that's a little silly and completely real: &lt;a href="https://github.com/javimosch/machin-game-mtlm-rpg-poc" rel="noopener noreferrer"&gt;a dungeon crawler&lt;/a&gt; where every typed intent — &lt;code&gt;light the torch&lt;/code&gt;, &lt;code&gt;go north&lt;/code&gt;, &lt;code&gt;equip the sword&lt;/code&gt; — is routed by a tenant head. The game is just another customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calibration: measured, including the failure
&lt;/h2&gt;

&lt;p&gt;The honest part: a head's out-of-box confidence is fit on synthetic validation data, and on &lt;em&gt;off-distribution&lt;/em&gt; real traffic softmax saturates — in one shadow deployment, 65/72 decisions sat at conf ≥0.99 while only 61.5% were right.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;refit_temp.py&lt;/code&gt; ships in the repo: it refits the head's temperature on ~50+ labeled rows of &lt;em&gt;your&lt;/em&gt; traffic, after which mean confidence tracks measured accuracy — and a head that hasn't earned trust degrades to honest abstention. "p=0.9 means right 90% of the time" is achievable on your data, not just ours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;7M params — it &lt;em&gt;routes&lt;/em&gt;, it does not reason. Delegation is built in.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;noul&lt;/code&gt;/&lt;code&gt;score&lt;/code&gt; answer fixed trained questions; arbitrary criteria text is the roadmap.&lt;/li&gt;
&lt;li&gt;Ambiguous human-judgment tasks need label volume, not a bigger model — a 0.6B web-pretrained backbone scored &lt;em&gt;worse&lt;/em&gt; than this 7M trunk on one fuzzy 3-way task.&lt;/li&gt;
&lt;li&gt;Chat replies are TinyStories-grade. It's a dispatcher, not a chatbot.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code + appliance: &lt;a href="https://github.com/javimosch/mtlm-router" rel="noopener noreferrer"&gt;github.com/javimosch/mtlm-router&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Weights: &lt;a href="https://huggingface.co/javimosch/mtlm-7m-router3s384" rel="noopener noreferrer"&gt;Hugging Face&lt;/a&gt; · &lt;a href="https://www.modelscope.ai/models/javimosch/mtlm-7m-router3s384" rel="noopener noreferrer"&gt;ModelScope&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Runtime: &lt;a href="https://github.com/javimosch/machin-anvil" rel="noopener noreferrer"&gt;machin-anvil&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tar &lt;/span&gt;xzf mtlm-router-&lt;span class="k"&gt;*&lt;/span&gt;.tar.gz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;mtlm-router-&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./start.sh
curl localhost:8097/v1/route &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"state":"remind me to stretch every hour"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>selfhosted</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Technical debt is a maintenance problem, not a coding problem — here's how AI agents help</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Thu, 17 Sep 2026 10:15:08 +0000</pubDate>
      <link>https://dev.to/javimosch/technical-debt-is-a-maintenance-problem-not-a-coding-problem-heres-how-ai-agents-help-hk8</link>
      <guid>https://dev.to/javimosch/technical-debt-is-a-maintenance-problem-not-a-coding-problem-heres-how-ai-agents-help-hk8</guid>
      <description>&lt;p&gt;We've all been in that repo. The one where &lt;code&gt;npm install&lt;/code&gt; prints 47 warnings, the README still references a &lt;code&gt;v1&lt;/code&gt; API that was renamed two years ago, three tests are skipped "for now," and the last meaningful commit on &lt;code&gt;master&lt;/code&gt; was a merge from a branch nobody remembers. You clone it, run it, and it kind of works — until it doesn't.&lt;/p&gt;

&lt;p&gt;We call this technical debt, but that framing is wrong. Debt implies you borrowed something on purpose and have a plan to pay it back. What most repos actually have is &lt;strong&gt;drift&lt;/strong&gt; — the slow, invisible accumulation of small mismatches between what the code does, what the docs say, what the dependencies expect, and what the tests assert. Nobody chose it. Nobody owns it. It just happens, because maintenance is unpaid labor and shipping features is paid labor.&lt;/p&gt;

&lt;p&gt;Here's the thing I've come to believe after maintaining enough projects: &lt;strong&gt;technical debt is not a coding problem. It's a maintenance problem.&lt;/strong&gt; And that distinction matters, because it changes what tooling can do about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "just write better code" doesn't fix it
&lt;/h2&gt;

&lt;p&gt;If tech debt were a coding problem, better engineers and better reviews would solve it. And sure, those help at the margins. But drift doesn't come from bad code — it comes from the gap between &lt;em&gt;when a change is made&lt;/em&gt; and &lt;em&gt;when the surrounding context catches up&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Consider a few examples I bet you recognize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stale dependencies.&lt;/strong&gt; A patch release of a transitive dep fixes a CVE. Nobody bumps it because nothing is broken &lt;em&gt;yet&lt;/em&gt;. Six months later you're on a version three majors behind and the upgrade is now a project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs out of sync.&lt;/strong&gt; You rename a function, update the call sites, and forget the README example. Or the architecture doc references a service that was deleted. The docs don't fail CI, so they rot silently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests that lie.&lt;/strong&gt; A test gets skipped during a refactor "to fix later." Later never comes. Now your green build is hiding a real regression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo drift across services.&lt;/strong&gt; Service A expects payload shape v2. Service B still sends v1. It works in dev because dev uses mocked data. Prod finds out at 2am.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are bugs in the code. They're failures of &lt;em&gt;synchronization&lt;/em&gt; — the ongoing work of keeping a repo coherent with itself and its environment. It's maintenance. And it's exactly the kind of work humans are bad at scheduling, because it never feels urgent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of a real solution
&lt;/h2&gt;

&lt;p&gt;If the problem is maintenance, the fix isn't a smarter linter or a one-off cleanup sprint. It's a &lt;strong&gt;continuous maintenance loop&lt;/strong&gt; — something that runs on a schedule, looks at the repo as a whole, and makes small, reviewable changes to keep it healthy.&lt;/p&gt;

&lt;p&gt;A practical loop looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Observe&lt;/strong&gt; — read the repo state: dependency manifests, test output, docs, recent commits, open issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide&lt;/strong&gt; — figure out what's drifted and what's worth fixing right now (prioritize security &amp;gt; tests &amp;gt; deps &amp;gt; docs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Act&lt;/strong&gt; — make the change: bump a version, update a doc example, un-skip and fix a test, open a PR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; — run the tests, the linter, the build. If it's red, fix it or revert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeat&lt;/strong&gt; — on a schedule, not when someone remembers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key insight is that steps 1, 2, and 4 are mostly mechanical, and step 3 is increasingly within reach of AI coding agents. You don't need a human to notice that &lt;code&gt;package-lock.json&lt;/code&gt; has a CVE advisory, or that the README's install command references a flag you removed. You need something that &lt;em&gt;does something about it&lt;/em&gt; without waiting for a sprint planning meeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  A pattern that actually works: agents as peers, not orchestrators
&lt;/h2&gt;

&lt;p&gt;Most "AI for maintenance" setups I've seen fall into the same trap: a single big prompt that says "fix my repo." That works once, badly, and then you forget it exists. The repos that stay healthy use a different pattern — multiple focused agents that each own a slice of the maintenance surface, coordinating as peers.&lt;/p&gt;

&lt;p&gt;Instead of one agent trying to understand everything, you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;deps agent&lt;/strong&gt; that watches for outdated/CVE'd packages and bumps them one at a time.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;docs agent&lt;/strong&gt; that diffs code against docs and rewrites the stale parts.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;tests agent&lt;/strong&gt; that finds skipped/failing tests and tries to fix them.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;hygiene agent&lt;/strong&gt; that looks for dead code, broken links, and config drift.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They don't report to a central brain. They share a message bus, see each other's work, and avoid stepping on the same files. If the deps agent is mid-PR on &lt;code&gt;package.json&lt;/code&gt;, the docs agent waits before touching the install instructions. This is closer to how a real on-call rotation works than how a "AI orchestrator" works.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete example
&lt;/h2&gt;

&lt;p&gt;Here's what this looks like in practice with &lt;a href="https://automaintainer.intrane.fr" rel="noopener noreferrer"&gt;AutoMaintainer&lt;/a&gt;, a daemon that runs this exact loop using AI agents over a peer-to-peer message bus. You register a repo with a plain-English focus and start the daemon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Register a repo and tell the agents what "healthy" means for it&lt;/span&gt;
am repo add https://github.com/you/myproject &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--focus&lt;/span&gt; &lt;span class="s2"&gt;"keep docs in sync with code, fix failing tests, bump outdated deps"&lt;/span&gt;

&lt;span class="c"&gt;# Enable it; runs happen on a schedule and open PRs for review&lt;/span&gt;
am repo &lt;span class="nb"&gt;enable&lt;/span&gt; &amp;lt;repo-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole setup. The daemon spawns an agent team per repo, each agent picks up its slice of the focus, and they start opening PRs. You review the PRs like you would any other. The agents handle the observe-decide-act-verify loop on a schedule; you stay in control of what merges.&lt;/p&gt;

&lt;p&gt;The focus string is doing real work here. "Keep docs in sync" means something different for a library than for a microservice, and you want to be able to say "don't touch the public API" or "prioritize the test suite over dep bumps this week" without rewriting tooling. Plain English as config is underrated.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this gets you, and what it doesn't
&lt;/h2&gt;

&lt;p&gt;Let's be honest about the tradeoffs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it gets you:&lt;/strong&gt; the boring 80% of maintenance happens without a human thinking about it. Deps stay current. Docs stop lying. Skipped tests get fixed or honestly deleted. You stop opening a repo after three months and finding it's a stranger. The PRs are small and reviewable, which means review is fast — you're not approving a 2,000-line "cleanup" bomb, you're glancing at a one-line version bump.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it doesn't get you:&lt;/strong&gt; it won't make architectural decisions for you. If your monolith needs to become services, no agent team is going to figure that out from a focus string. It also won't replace good judgment about &lt;em&gt;when&lt;/em&gt; to take a breaking change. What it does is keep the floor clean so that when you do need to make a big move, you're not wading through six months of drift to get there.&lt;/p&gt;

&lt;p&gt;The mental shift is this: stop treating maintenance as the thing you do when everything else is done (it never is), and start treating it as a background process that runs whether or not anyone's watching. That's literally what daemons are for.&lt;/p&gt;

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

&lt;p&gt;If you have a repo that's been quietly rotting — and we all do — point a maintenance loop at it for a week and see what comes back. You'll either get a pile of small, useful PRs, or you'll learn something about what "healthy" actually means for that project. Both are wins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install and register your first repo&lt;/span&gt;
am repo add https://github.com/you/myproject &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--focus&lt;/span&gt; &lt;span class="s2"&gt;"keep docs in sync with code, fix failing tests, bump outdated deps"&lt;/span&gt;
am repo &lt;span class="nb"&gt;enable&lt;/span&gt; &amp;lt;repo-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hosted: &lt;a href="https://automaintainer.intrane.fr" rel="noopener noreferrer"&gt;https://automaintainer.intrane.fr&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Maintenance isn't going to stop being unpaid labor. But it can stop being &lt;em&gt;invisible&lt;/em&gt; labor — and that's most of the battle.&lt;/p&gt;

</description>
      <category>database</category>
      <category>testing</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>100 AI Image Tools: The Complete List (2026)</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Mon, 14 Sep 2026 07:27:18 +0000</pubDate>
      <link>https://dev.to/javimosch/100-ai-image-tools-the-complete-list-2026-5fkn</link>
      <guid>https://dev.to/javimosch/100-ai-image-tools-the-complete-list-2026-5fkn</guid>
      <description>&lt;p&gt;This is the complete list of all 100 AI image tools available on Crevisto. Each tool is pre-tuned for a specific use case — no prompting, no rerolling. Pick a tool, upload a photo, get the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Photo &amp;amp; Portrait Tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/linkedin-avatar" rel="noopener noreferrer"&gt;LinkedIn Avatar&lt;/a&gt; — Professional headshot from a selfie&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/linkedin-avatar" rel="noopener noreferrer"&gt;Profile Picture&lt;/a&gt; — AI-enhanced profile pictures&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/age-progression" rel="noopener noreferrer"&gt;Age Progression&lt;/a&gt; — See yourself at any age&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/gender-swap" rel="noopener noreferrer"&gt;Gender Swap&lt;/a&gt; — Swap gender in any photo&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/gender-swap" rel="noopener noreferrer"&gt;Face Swap&lt;/a&gt; — Swap faces in photos&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/photo-restoration" rel="noopener noreferrer"&gt;Photo Restoration&lt;/a&gt; — Fix old and damaged photos&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/image-upscaler" rel="noopener noreferrer"&gt;Image Upscaler&lt;/a&gt; — Upscale images with AI&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/background-remover" rel="noopener noreferrer"&gt;Background Remover&lt;/a&gt; — Remove backgrounds with AI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Art &amp;amp; Style Tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/ghibli-style" rel="noopener noreferrer"&gt;Ghibli Style&lt;/a&gt; — Studio Ghibli art style&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/photo-to-painting" rel="noopener noreferrer"&gt;Oil Painting&lt;/a&gt; — Turn photos into oil paintings&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/photo-to-painting" rel="noopener noreferrer"&gt;Watercolor&lt;/a&gt; — Watercolor painting effect&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/sketch-to-image" rel="noopener noreferrer"&gt;Sketch Maker&lt;/a&gt; — Convert photos to pencil sketches&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/pixel-art" rel="noopener noreferrer"&gt;Pixel Art&lt;/a&gt; — Retro game pixel art&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/cartoon-portrait" rel="noopener noreferrer"&gt;Cartoonify&lt;/a&gt; — Turn photos into cartoons&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Social Media Tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/instagram-story-bg" rel="noopener noreferrer"&gt;Instagram Filter&lt;/a&gt; — Instagram-style filters&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools" rel="noopener noreferrer"&gt;TikTok Style&lt;/a&gt; — TikTok aesthetic&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/youtube-thumbnail" rel="noopener noreferrer"&gt;YouTube Thumbnail&lt;/a&gt; — Generate YouTube thumbnails&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/social-banner" rel="noopener noreferrer"&gt;Social Banner&lt;/a&gt; — Create social media banners&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Business &amp;amp; Design Tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/logo-maker" rel="noopener noreferrer"&gt;Logo Maker&lt;/a&gt; — Design a logo in 60 seconds&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/product-studio" rel="noopener noreferrer"&gt;Product Photo&lt;/a&gt; — Enhanced product photography&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/blog-header" rel="noopener noreferrer"&gt;Blog Header&lt;/a&gt; — Generate blog header images&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fun &amp;amp; Viral Tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/action-figure" rel="noopener noreferrer"&gt;Action Figure Generator&lt;/a&gt; — Turn photos into collectible toys&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/pet-pixar" rel="noopener noreferrer"&gt;Pet Pixar&lt;/a&gt; — Turn pets into Pixar characters&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crevisto.com/tools/baby-generator" rel="noopener noreferrer"&gt;AI Baby Generator&lt;/a&gt; — See your future baby&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to use them
&lt;/h2&gt;

&lt;p&gt;Every tool works the same way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://crevisto.com/tools" rel="noopener noreferrer"&gt;crevisto.com/tools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pick a tool&lt;/li&gt;
&lt;li&gt;Upload a photo (or enter text for text-based tools)&lt;/li&gt;
&lt;li&gt;Click "Generate"&lt;/li&gt;
&lt;li&gt;Download the result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;5 free credits, no credit card required. Credits never expire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the CLI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://crevisto.com/install.sh | sh
crevisto trial
crevisto tools
crevisto generate action-figure &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./selfie.jpg &lt;span class="nt"&gt;--output&lt;/span&gt; ./result.webp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://crevisto.com" rel="noopener noreferrer"&gt;Web app&lt;/a&gt; · &lt;a href="https://crevisto.com/tools" rel="noopener noreferrer"&gt;All 100 tools&lt;/a&gt; · &lt;a href="https://crevisto.com/docs" rel="noopener noreferrer"&gt;CLI docs&lt;/a&gt; · &lt;a href="https://github.com/javimosch/crevisto" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tools</category>
      <category>list</category>
      <category>2026</category>
    </item>
    <item>
      <title>Crevisto CLI: A Developer's Guide to Terminal-Based AI Image Generation</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Mon, 14 Sep 2026 07:21:29 +0000</pubDate>
      <link>https://dev.to/javimosch/crevisto-cli-a-developers-guide-to-terminal-based-ai-image-generation-1g2m</link>
      <guid>https://dev.to/javimosch/crevisto-cli-a-developers-guide-to-terminal-based-ai-image-generation-1g2m</guid>
      <description>&lt;p&gt;Most AI image tools live in the browser. That's fine for casual use, but developers need something different: scriptable, pipeable, automatable. The Crevisto CLI brings 100 AI image tools to the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://crevisto.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Single binary, no runtime, no dependencies. Works on Linux, macOS, and Windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start a free trial (5 credits, no credit card)&lt;/span&gt;
crevisto trial

&lt;span class="c"&gt;# List all 100 tools&lt;/span&gt;
crevisto tools

&lt;span class="c"&gt;# Generate an action figure from a photo&lt;/span&gt;
crevisto generate action-figure &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./selfie.jpg &lt;span class="nt"&gt;--output&lt;/span&gt; ./result.webp

&lt;span class="c"&gt;# Generate a Ghibli-style image&lt;/span&gt;
crevisto generate ghibli-style &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./landscape.jpg &lt;span class="nt"&gt;--output&lt;/span&gt; ./ghibli.webp

&lt;span class="c"&gt;# Generate a LinkedIn headshot&lt;/span&gt;
crevisto generate linkedin-avatar &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./selfie.jpg &lt;span class="nt"&gt;--output&lt;/span&gt; ./headshot.webp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  BYOK: Unlimited generations at cost
&lt;/h2&gt;

&lt;p&gt;Plug in your OpenRouter API key and generate unlimited images at the model's actual cost. Zero credit consumption from Crevisto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set your OpenRouter API key&lt;/span&gt;
crevisto config &lt;span class="nb"&gt;set &lt;/span&gt;openrouter_key sk-or-v1-...

&lt;span class="c"&gt;# Generate with BYOK (no credits consumed)&lt;/span&gt;
crevisto generate action-figure &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./selfie.jpg &lt;span class="nt"&gt;--byok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scripting and automation
&lt;/h2&gt;

&lt;p&gt;The CLI outputs JSON, making it easy to script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate and parse the result&lt;/span&gt;
&lt;span class="nv"&gt;RESULT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;crevisto generate logo-maker &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"MyBrand"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; ./logo.webp &lt;span class="nt"&gt;--json&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$RESULT&lt;/span&gt; | jq &lt;span class="s1"&gt;'.output_url'&lt;/span&gt;

&lt;span class="c"&gt;# Batch process a directory&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;photo &lt;span class="k"&gt;in&lt;/span&gt; ./photos/&lt;span class="k"&gt;*&lt;/span&gt;.jpg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;crevisto generate ghibli-style &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$photo&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; &lt;span class="s2"&gt;"./output/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$photo&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; .jpg&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.webp"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Available tools
&lt;/h2&gt;

&lt;p&gt;100 niche tools, each pre-tuned for a specific use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/action-figure" rel="noopener noreferrer"&gt;Action Figure Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/ghibli-style" rel="noopener noreferrer"&gt;Ghibli Style&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/linkedin-avatar" rel="noopener noreferrer"&gt;LinkedIn Avatar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/logo-maker" rel="noopener noreferrer"&gt;Logo Maker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/photo-restoration" rel="noopener noreferrer"&gt;Photo Restoration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/pet-pixar" rel="noopener noreferrer"&gt;Pet Pixar Style&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/baby-generator" rel="noopener noreferrer"&gt;AI Baby Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/gender-swap" rel="noopener noreferrer"&gt;Gender Swap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/age-progression" rel="noopener noreferrer"&gt;Age Progression&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/gender-swap" rel="noopener noreferrer"&gt;Face Swap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/pixel-art" rel="noopener noreferrer"&gt;Pixel Art&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/photo-to-painting" rel="noopener noreferrer"&gt;Oil Painting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/photo-to-painting" rel="noopener noreferrer"&gt;Watercolor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/sketch-to-image" rel="noopener noreferrer"&gt;Sketch Maker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crevisto.com/tools/cartoon-portrait" rel="noopener noreferrer"&gt;Cartoonify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;...and 85 more. See &lt;code&gt;crevisto tools&lt;/code&gt; or &lt;a href="https://crevisto.com/tools" rel="noopener noreferrer"&gt;the full list&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;p&gt;Full CLI docs at &lt;a href="https://crevisto.com/docs" rel="noopener noreferrer"&gt;crevisto.com/docs&lt;/a&gt;. Source on &lt;a href="https://github.com/javimosch/crevisto" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://crevisto.com/install.sh | sh
crevisto trial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5 free credits, no credit card, no subscription. Credits never expire.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>ai</category>
      <category>devtools</category>
      <category>terminal</category>
    </item>
    <item>
      <title>I built Crevisto — 100 curated AI image tools in one platform</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Sun, 13 Sep 2026 19:22:44 +0000</pubDate>
      <link>https://dev.to/javimosch/i-built-crevisto-100-curated-ai-image-tools-in-one-platform-2ckc</link>
      <guid>https://dev.to/javimosch/i-built-crevisto-100-curated-ai-image-tools-in-one-platform-2ckc</guid>
      <description>&lt;p&gt;Most AI image platforms give you a generic "generate image" box and leave you to craft the perfect prompt. Crevisto takes a different approach: 100 specific tools, each tuned for a particular use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the catalog
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Viral tools&lt;/strong&gt;: Action Figure Generator (890K+ TikTok videos), AI Baby Generator, Ghibli Style, Gender Swap, Age Progression&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Photo editing&lt;/strong&gt;: Background Remover, Image Upscaler, Object Remover, Photo Restoration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional&lt;/strong&gt;: LinkedIn Avatar, Resume Photo, Product Studio, Passport Photo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creative&lt;/strong&gt;: Photo to Painting, Renaissance Portrait, Comic Book Style, Magazine Cover, Movie Poster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design&lt;/strong&gt;: Logo Maker, Book Cover, Wedding Invitation, Tattoo Design, Sneaker Design&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ol&gt;
&lt;li&gt;Pick a tool&lt;/li&gt;
&lt;li&gt;Upload a photo or describe what you want&lt;/li&gt;
&lt;li&gt;Generate — results in 30-90 seconds&lt;/li&gt;
&lt;li&gt;Download or share&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Pricing model
&lt;/h2&gt;

&lt;p&gt;No subscription. You get 5 free credits on signup, then pay as you go. Credits never expire. There's also BYOK (bring your own OpenRouter key) for unlimited generations.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLI-first
&lt;/h2&gt;

&lt;p&gt;Crevisto is also a CLI tool — generate images from your terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
curl -s https://crevisto.com/install.sh | bash&lt;br&gt;
crevisto login&lt;br&gt;
crevisto generate action-figure --photo selfie.jpg&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The CLI is open source and works on macOS, Linux, and Windows.&lt;/p&gt;

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

&lt;p&gt;5 free credits, no credit card: &lt;a href="https://crevisto.com/register" rel="noopener noreferrer"&gt;https://crevisto.com/register&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full catalog: &lt;a href="https://crevisto.com/tools" rel="noopener noreferrer"&gt;https://crevisto.com/tools&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>go</category>
      <category>selfhosted</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Building an agent-first document database in 75KB</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 11 Sep 2026 10:26:37 +0000</pubDate>
      <link>https://dev.to/javimosch/building-an-agent-first-document-database-in-75kb-1b75</link>
      <guid>https://dev.to/javimosch/building-an-agent-first-document-database-in-75kb-1b75</guid>
      <description>&lt;p&gt;Most databases are built for humans. They have consoles, dashboards, connection pools, GUI clients. They expect you to know what a tablespace is. They bill you through a web form with a credit card.&lt;/p&gt;

&lt;p&gt;Agents don't need any of that. An agent needs JSON in, JSON out, and a bill it can settle itself.&lt;/p&gt;

&lt;p&gt;This is the story of &lt;a href="https://github.com/javimosch/grange" rel="noopener noreferrer"&gt;grange&lt;/a&gt; — a document database written in &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;machin&lt;/a&gt;, a stack-based language that compiles to a single static binary. It has crash-safe WAL, indexes with O(1) aggregate registers, cold storage for datasets bigger than your RAM, and a hosted instance where signup is one curl with a prepaid wallet. No card on file, no subscription, no console.&lt;/p&gt;

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

&lt;p&gt;I build AI agents. Agents produce structured data — leads, transcripts, tool outputs, search results — and they need somewhere to put it. The options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQLite&lt;/strong&gt;: excellent, but it's a relational database. Agents think in JSON, not in &lt;code&gt;CREATE TABLE&lt;/code&gt; migrations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postgres/Mongo&lt;/strong&gt;: production-grade, but they need a server, a connection string, a password, and a human to provision them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase/Supabase&lt;/strong&gt;: hosted and easy, but they expect a human with a credit card and a dashboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I wanted was a database that an agent could provision itself, query with plain JSON, and pay for per-call — and that I could also self-host as a single binary when the hosted rail didn't fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The language: machin (MFL)
&lt;/h2&gt;

&lt;p&gt;grange is written in &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;machin&lt;/a&gt; (MFL — Machin Forth-like Language), a stack-based language that compiles to native code via a C backend. The choice was deliberate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single binary&lt;/strong&gt;: machin compiles to one static binary (musl, ~7.5 MB). No runtime, no cgo, no glibc floor. It runs on Alpine and &lt;code&gt;FROM scratch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero goroutines&lt;/strong&gt;: the server is a single actor — a sequential accept loop. There is nothing to race on, and machin's inferred data-race analysis verifies that on every build with no annotations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maps are reference types&lt;/strong&gt;: parking and restoring a collection's whole state is a handful of map assignments, so collection switching is O(1).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off is honest: a single-actor server means one slow query blocks everyone. That's the concurrency ceiling, and it's documented in &lt;code&gt;docs/CONCURRENCY.md&lt;/code&gt;. For agent workloads — short, indexed, bursty — it's fine. For a thousand concurrent human users running ad-hoc analytics, it's not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crash-safe by construction
&lt;/h2&gt;

&lt;p&gt;Every commit is one immutable, checksummed WAL chunk. The on-disk layout is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;db&amp;gt;/&amp;lt;coll&amp;gt;/seg-&amp;lt;gen&amp;gt;.grg       immutable compacted snapshot
&amp;lt;db&amp;gt;/&amp;lt;coll&amp;gt;/wal-&amp;lt;gen&amp;gt;-&amp;lt;n&amp;gt;.grg   immutable WAL chunk, one per commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every &lt;code&gt;.grg&lt;/code&gt; file ends with a &lt;code&gt;#|&amp;lt;nrecs&amp;gt;|&amp;lt;sha256:12&amp;gt;&lt;/code&gt; trailer. MFL has no file append or rename, so grange never mutates a file: a commit writes a fresh chunk, compaction writes a fresh segment (verified by re-read before anything is deleted).&lt;/p&gt;

&lt;p&gt;Recovery is simple: load the newest valid segment, replay its valid chunks in order, drop anything torn. &lt;code&gt;kill -9&lt;/code&gt; at any moment leaves exactly the committed prefix.&lt;/p&gt;

&lt;p&gt;This is proven, not claimed. &lt;code&gt;make crash&lt;/code&gt; runs 5 rounds of mid-flight SIGKILL, and recovered counts must be exact commit-batch multiples. The repo ships the harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(1) aggregates: the trick that makes group-by free
&lt;/h2&gt;

&lt;p&gt;This is the feature I'm most proud of. When you declare an index, you can also declare aggregate registers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grange index &lt;span class="nt"&gt;--db&lt;/span&gt; ./data &lt;span class="nt"&gt;--coll&lt;/span&gt; leads &lt;span class="nt"&gt;--field&lt;/span&gt; status &lt;span class="nt"&gt;--sums&lt;/span&gt; score
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This maintains per-group &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;sum&lt;/code&gt;, and &lt;code&gt;avg&lt;/code&gt; incrementally at write time. A group-by query is a map lookup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grange agg &lt;span class="nt"&gt;--db&lt;/span&gt; ./data &lt;span class="nt"&gt;--group-by&lt;/span&gt; status &lt;span class="nt"&gt;--sum&lt;/span&gt; score
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result: &lt;strong&gt;group-by count/sum/avg × 1000 takes &amp;lt;1 ms&lt;/strong&gt;. Not because the query is fast — because the query doesn't scan. The answer was computed at write time and stored in the index.&lt;/p&gt;

&lt;p&gt;SQLite, doing the same group-by × 1000, takes 49 seconds.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;workload&lt;/th&gt;
&lt;th&gt;grange&lt;/th&gt;
&lt;th&gt;SQLite&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;bulk insert, 2 indexes maintained&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;278k docs/s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;25k rows/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;point get (avg of 1000)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5 µs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;indexed count × 1000&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&amp;lt;1 ms&lt;/strong&gt; (O(1) register)&lt;/td&gt;
&lt;td&gt;1,937 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;group-by count/sum/avg × 1000&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&amp;lt;1 ms&lt;/strong&gt; (O(1) registers)&lt;/td&gt;
&lt;td&gt;49,114 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;range count × 1000&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&amp;lt;1 ms&lt;/strong&gt; (after one-time 79 ms sort)&lt;/td&gt;
&lt;td&gt;257 ms (indexed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;full scan, no index (worst case)&lt;/td&gt;
&lt;td&gt;61 ms&lt;/td&gt;
&lt;td&gt;8 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The one row SQLite wins is the unindexed scan — typed columns beat per-doc JSON extraction. The answer is &lt;code&gt;grange index&lt;/code&gt;: one command, and that query class becomes O(1) or O(bucket) forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cold storage: 200k docs in 4.4 MB of RAM
&lt;/h2&gt;

&lt;p&gt;Hot collections hold everything in memory. That's fast but doesn't scale beyond your RAM. Cold collections are disk-resident:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grange cold &lt;span class="nt"&gt;--db&lt;/span&gt; ./data &lt;span class="nt"&gt;--coll&lt;/span&gt; archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cold mode uses hash-partitioned page files (the same checksummed write-once format), a bounded memtable, and streaming scans. Measured at 200k docs: &lt;strong&gt;4.4 MB RSS vs 89.9 MB hot&lt;/strong&gt; in a fresh process.&lt;/p&gt;

&lt;p&gt;Cold collections take secondary indexes too. The index is written as value-partitioned page files, so an equality lookup reads ONE index page plus only the data pages holding its candidates. A selective lookup on 100k cold docs goes from 112 ms to 7 ms (15×).&lt;/p&gt;

&lt;p&gt;Cold collections also take ordered (range) indexes — &lt;code&gt;grange index --coll events --field ts --range&lt;/code&gt; — which store values sorted across pages with min/max boundary files. A range query reads only the pages whose interval overlaps it. This came from a real workload: mirroring a live analytics database showed every dashboard question is a time range, and those were full scans.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hosted model: your agent pays its own bill
&lt;/h2&gt;

&lt;p&gt;The hosted instance at &lt;a href="https://grange.intrane.fr" rel="noopener noreferrer"&gt;grange.intrane.fr&lt;/a&gt; has a signup flow designed for agents, not humans:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get an isolated, metered namespace — the wallet IS the signup&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://grange.intrane.fr/tenants &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Peage-Wallet: pw_...'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"my agent"}'&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; {"tenant":"t...","token":"gt_...", "pricing":{...}}&lt;/span&gt;

&lt;span class="c"&gt;# Put a document&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://grange.intrane.fr/put &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer gt_...'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"coll":"leads","doc":{"co":"acme","score":9}}'&lt;/span&gt;

&lt;span class="c"&gt;# Query it&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'https://grange.intrane.fr/agg?coll=leads&amp;amp;group-by=co&amp;amp;sum=score'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer gt_...'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tenant gets a separate database directory on disk — separate WAL, separate collections, separate indexes. The token is the only scope key. Storage is metered at €0.15/GB/month, first 50 MB free, accrued continuously and charged to the wallet via &lt;a href="https://peage.intrane.fr" rel="noopener noreferrer"&gt;peage&lt;/a&gt;. No subscription, no card on file.&lt;/p&gt;

&lt;p&gt;The agent contract is published at &lt;a href="https://grange.intrane.fr/llms.txt" rel="noopener noreferrer"&gt;grange.intrane.fr/llms.txt&lt;/a&gt; — the full API surface, written for machines, not for browsers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dogfooding: this page runs on grange
&lt;/h2&gt;

&lt;p&gt;The landing page's own subscribe form is a paying tenant of the hosted instance. The flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User enters email on the landing form&lt;/li&gt;
&lt;li&gt;Form POSTs to &lt;code&gt;subscribe.grange.intrane.fr/subscribe&lt;/code&gt; (a 130-line machin app)&lt;/li&gt;
&lt;li&gt;The subscribe service uses the machin client SDK to PUT the email into hosted grange&lt;/li&gt;
&lt;li&gt;Every subscriber email is a document in the &lt;code&gt;subscribers&lt;/code&gt; collection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The count is live and public:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://subscribe.grange.intrane.fr/count
&lt;span class="c"&gt;# -&amp;gt; {"ok":true,"data":{"subscribers":4}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a demo. It's a real workload — small, but real. The subscribe service is a separate process (a grange actor calling its own HTTP API would deadlock), which is also the honest shape of a customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's verified
&lt;/h2&gt;

&lt;p&gt;The repo ships 21 test harnesses and 388 unit assertions. The interesting ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Differential fuzz&lt;/strong&gt; (&lt;code&gt;make fuzz&lt;/code&gt;): the same pseudo-random op stream is applied to a hot collection (oracle) and a cold collection, comparing entire visible state after every op. 12,000 ops across 10 seeds, zero divergence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutation-tested harness&lt;/strong&gt;: the fuzzer was validated by injecting four deliberate bugs. The first version caught only three; the state comparison was strengthened until all four fail loudly. A test that never fails proves nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crash injection&lt;/strong&gt; (&lt;code&gt;make crash&lt;/code&gt;): &lt;code&gt;kill -9&lt;/code&gt; mid-flight on cold collections, where a commit spans many files. Recovery must open cleanly, agree with filtered queries, accept writes, and survive a compaction of the recovered state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrity check&lt;/strong&gt; (&lt;code&gt;grange verify&lt;/code&gt;): walks every file's checksum and record stream, cross-checks cold manifests against pages, confirms indexes agree with data. Detects a flipped byte, a truncated page, a missing index page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The honest trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-actor server&lt;/strong&gt;: one slow query blocks everyone. Fine for agent workloads, not fine for concurrent human analytics. Concurrent readers are future work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unindexed scans are slower than SQLite&lt;/strong&gt;: typed columns beat per-doc JSON extraction. The answer is indexes — but you have to declare them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nobody but the author has run it&lt;/strong&gt;: the repo has 0 GitHub stars. The operations verdict in &lt;code&gt;docs/OPERATIONS.md&lt;/code&gt; says it's suitable for a service whose failure you can tolerate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux x86-64 only&lt;/strong&gt;: a database server needs POSIX, and machin cross-compiles to wasm and Windows, but those targets aren't useful for a server.&lt;/li&gt;
&lt;/ul&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Self-hosted&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; grange https://github.com/javimosch/grange/releases/latest/download/grange-linux-x86_64
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x grange
./grange guide          &lt;span class="c"&gt;# the version-exact feature catalog&lt;/span&gt;

&lt;span class="c"&gt;# Or hosted — skip the install&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://grange.intrane.fr/llms.txt   &lt;span class="c"&gt;# the full contract, written for agents&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SDKs: &lt;a href="https://pypi.org/project/grange-db/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/grange-db" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;, Go, machin. All MIT.&lt;/p&gt;

</description>
      <category>database</category>
      <category>go</category>
      <category>selfhosted</category>
      <category>architecture</category>
    </item>
    <item>
      <title>A Stranger Filed a Bug. My AI Fixed It While I Slept.</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 04 Sep 2026 08:46:20 +0000</pubDate>
      <link>https://dev.to/javimosch/a-stranger-filed-a-bug-my-ai-fixed-it-while-i-slept-1</link>
      <guid>https://dev.to/javimosch/a-stranger-filed-a-bug-my-ai-fixed-it-while-i-slept-1</guid>
      <description>&lt;p&gt;On July 25, 2026, a developer I'd never met opened &lt;a href="https://github.com/javimosch/supercli/issues/362" rel="noopener noreferrer"&gt;issue #362&lt;/a&gt; on my open-source project, &lt;a href="https://github.com/javimosch/supercli" rel="noopener noreferrer"&gt;SuperCLI&lt;/a&gt;. They ran the install script. It failed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sc-machin: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Their Linux distro shipped an older glibc. My release binaries were dynamically linked against a newer one. Classic portability bug — trivial to fix once you know the cause, but invisible until someone on a different distro tries your tool.&lt;/p&gt;

&lt;p&gt;On August 8, the issue was closed. The fix was merged. Tested. Verified. Shipped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I didn't touch it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened between July 25 and August 8
&lt;/h2&gt;

&lt;p&gt;My &lt;a href="https://automaintainer.intrane.fr" rel="noopener noreferrer"&gt;AutoMaintainer&lt;/a&gt; fleet was watching the SuperCLI repo. When issue #362 came in, the scheduler picked it up on its next maintenance cycle — the same way it picks up any open issue on a repo it maintains.&lt;/p&gt;

&lt;p&gt;Here's what the agent did, step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the issue&lt;/strong&gt; — parsed the error, identified &lt;code&gt;GLIBC_2.38 not found&lt;/code&gt; as the root cause&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oriented in the codebase&lt;/strong&gt; — found the GitHub Actions release workflow that builds Linux binaries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnosed the fix&lt;/strong&gt; — binaries were dynamically linked; fix was to build statically with &lt;code&gt;musl-gcc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implemented the change&lt;/strong&gt; — updated the workflow to install &lt;code&gt;musl-tools&lt;/code&gt;, build with &lt;code&gt;CC=musl-gcc --static&lt;/code&gt;, and verify the binary is statically linked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bumped the version&lt;/strong&gt; — updated install scripts and README URLs to &lt;code&gt;v0.2.1-machin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opened a PR&lt;/strong&gt; — &lt;a href="https://github.com/javimosch/supercli/pull/364" rel="noopener noreferrer"&gt;PR #364&lt;/a&gt;, with &lt;code&gt;Fixes #362&lt;/code&gt; so GitHub auto-closes on merge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The merger reviewed it&lt;/strong&gt; — my &lt;a href="https://blog.intrane.fr/the-ratchet-how-my-ai-fleet-merges-its-own-prs" rel="noopener noreferrer"&gt;ratchet merger&lt;/a&gt; evaluated the diff: 4 files, 13 insertions, 4 deletions. Small, safe type (&lt;code&gt;fix:&lt;/code&gt;), CI-config-only. It passed the strict gate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merged&lt;/strong&gt; — issue auto-closed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No human wrote a line of the fix. No human reviewed the diff. No human clicked merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;This wasn't a toy bug on a toy project. SuperCLI is a real tool with real users — 54 stars, forks, and at least one person on a machine called &lt;code&gt;ukhan-ai&lt;/code&gt; who needed it to work.&lt;/p&gt;

&lt;p&gt;The traditional open-source maintainer loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Someone files an issue&lt;/li&gt;
&lt;li&gt;You see it (maybe days later — you have a job, other repos)&lt;/li&gt;
&lt;li&gt;You reproduce it (switch to their distro? spin up a container?)&lt;/li&gt;
&lt;li&gt;You diagnose it&lt;/li&gt;
&lt;li&gt;You fix it&lt;/li&gt;
&lt;li&gt;You test it&lt;/li&gt;
&lt;li&gt;You open a PR&lt;/li&gt;
&lt;li&gt;You review it&lt;/li&gt;
&lt;li&gt;You merge it&lt;/li&gt;
&lt;li&gt;You release&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps 1 through 9 took &lt;strong&gt;zero human hours&lt;/strong&gt;. The agent compressed the entire maintainer loop into a single autonomous cycle. I found out when I checked my GitHub notifications the next morning and saw a closed issue with a merged PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  The diff
&lt;/h2&gt;

&lt;p&gt;The fix itself is unremarkable. That's the point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;.github/workflows/sc-machin-release.yml | 11 ++++++++++-
&lt;span class="p"&gt;README.md                               |  2 +-
supercli-machin-cli/README.md           |  2 +-
supercli-machin-cli/install.sh          |  2 +-
4 files changed, 13 insertions(+), 4 deletions(-)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install &lt;code&gt;musl-tools&lt;/code&gt;. Build with &lt;code&gt;CC=musl-gcc --static&lt;/code&gt;. Verify the binary is statically linked. Bump the version. That's it.&lt;/p&gt;

&lt;p&gt;The agent didn't over-engineer it. It didn't add a Docker-based cross-distro test matrix. It didn't refactor the release workflow. It made the &lt;em&gt;smallest safe diff&lt;/em&gt; that fixed the issue — which is exactly what I would have done.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the agent didn't do
&lt;/h2&gt;

&lt;p&gt;It didn't reply to the issue. It didn't comment on the PR with a human persona. It didn't pretend to be a person. The PR description is transparent: &lt;em&gt;"Automated maintenance run by automaintainer."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It also didn't scope-creep. The instructions are explicit: &lt;em&gt;"One focused fix is a complete win. Do not scope-creep."&lt;/em&gt; It could have noticed three other open issues and tried to fix them all in one PR. It fixed #362 and stopped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I actually did
&lt;/h2&gt;

&lt;p&gt;I configured AutoMaintainer to watch the repo. I set the safety rules the merger uses to decide what's safe to auto-merge. I wrote the focus prompt that tells the agent what the project is about.&lt;/p&gt;

&lt;p&gt;That's the job now. Not writing fixes — writing the rules that let an AI write fixes safely. Not reviewing every PR — defining the boundary between "the agent can handle this" and "this needs a human."&lt;/p&gt;

&lt;p&gt;The maintainer's role is moving upstream. From &lt;em&gt;fixing bugs&lt;/em&gt; to &lt;em&gt;designing the system that fixes bugs&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this goes next
&lt;/h2&gt;

&lt;p&gt;One issue, one fix, one merge. It's a small thing. But it's a small thing that happened without me — while I was asleep, on a repo with real users, for a bug filed by someone I've never met.&lt;/p&gt;

&lt;p&gt;The open-source maintainer burnout problem is real. The bottleneck has never been writing the fix — it's been the cognitive load of context-switching, reproducing, diagnosing, and following up across dozens of issues. If an AI agent can compress that loop into minutes and leave the human to handle only the judgment calls that actually need judgment...&lt;/p&gt;

&lt;p&gt;That's the future I'm building toward. And as of August 8, it's not theoretical anymore. It shipped.&lt;/p&gt;

&lt;p&gt;Full trail: &lt;a href="https://github.com/javimosch/supercli/issues/362" rel="noopener noreferrer"&gt;issue #362&lt;/a&gt; → &lt;a href="https://github.com/javimosch/supercli/pull/364" rel="noopener noreferrer"&gt;PR #364&lt;/a&gt; → &lt;a href="https://github.com/javimosch/supercli" rel="noopener noreferrer"&gt;SuperCLI repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to point AutoMaintainer at your own repos: &lt;a href="https://automaintainer.intrane.fr" rel="noopener noreferrer"&gt;automaintainer.intrane.fr&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://blog.intrane.fr/stranger-filed-bug-ai-fixed-it-while-i-slept" rel="noopener noreferrer"&gt;blog.intrane.fr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
    <item>
      <title>listen() returns -1 on bind failure in machin</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 04 Sep 2026 07:25:38 +0000</pubDate>
      <link>https://dev.to/javimosch/listen-returns-1-on-bind-failure-in-machin-3nli</link>
      <guid>https://dev.to/javimosch/listen-returns-1-on-bind-failure-in-machin-3nli</guid>
      <description>&lt;h2&gt;
  
  
  listen() returns -1 on bind failure in machin
&lt;/h2&gt;

&lt;p&gt;A small release just landed in machin. The headline is one line, but it closes a real gap: &lt;code&gt;listen()&lt;/code&gt; now returns &lt;code&gt;-1&lt;/code&gt; when the port can't be bound, so the guard you write around the return value is actually meaningful instead of silently misleading.&lt;/p&gt;

&lt;p&gt;Before this, code that looked defensive wasn't really defending anything — the failure path never triggered, so a bind error could flow forward as if the socket were live. Now the failure is surfaced as &lt;code&gt;-1&lt;/code&gt;, and existing &lt;code&gt;if (port &amp;lt; 0)&lt;/code&gt; style checks do what they read like they do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;The diff is 12 files changed, +126/-8, and it's deliberately consistent across the spec, the implementation, the docs, and the examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SPEC.md&lt;/code&gt; — documents that &lt;code&gt;listen()&lt;/code&gt; returns &lt;code&gt;-1&lt;/code&gt; when the port can't be bound.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;codegen.go&lt;/code&gt; — the generated binding code now propagates bind failure as &lt;code&gt;-1&lt;/code&gt; instead of a value that hides the error.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/LANGUAGE.md&lt;/code&gt; — language reference updated to match the spec.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;examples/complex/http_server.mfl&lt;/code&gt; — example updated so the guard around &lt;code&gt;listen()&lt;/code&gt; is real.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;examples/complex/json_api.mfl&lt;/code&gt; — same fix applied to the JSON API example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point of touching the spec, the codegen, the docs, and both examples in one commit is that the behavior, the contract, and the teaching material all agree after this. There's no window where the docs promise one thing and the compiler emits another.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;This is the kind of fix that's easy to dismiss as cosmetic because it doesn't add a feature. It isn't cosmetic. A guard that never fires is worse than no guard at all: it makes the code look handled, so nobody looks closer, and the real failure mode shows up later as a mystery — a server that "started" but isn't listening, a port collision that silently produces a dead socket, a test that passes against the wrong process.&lt;/p&gt;

&lt;p&gt;Returning &lt;code&gt;-1&lt;/code&gt; on bind failure is the smallest change that makes the existing error-handling pattern honest. If you were already writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;port := listen(addr)
if port &amp;lt; 0 {
    // handle bind failure
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…then this release is the one that makes that branch reachable. If you weren't guarding the return value, now is a good time to start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Repo and full diff: &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;https://github.com/javimosch/machin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>testing</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Felipe — The AI CEO That Reviews My Pull Requests</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Thu, 03 Sep 2026 03:33:53 +0000</pubDate>
      <link>https://dev.to/javimosch/felipe-the-ai-ceo-that-reviews-my-pull-requests-286n</link>
      <guid>https://dev.to/javimosch/felipe-the-ai-ceo-that-reviews-my-pull-requests-286n</guid>
      <description>&lt;p&gt;I have an AI fleet that opens pull requests on my repos every day. It builds, tests, and verifies each one before pushing. But someone still has to review and merge them. That someone was me — and I was the bottleneck.&lt;/p&gt;




&lt;p&gt;My &lt;a href="https://github.com/javimosch/automaintainer" rel="noopener noreferrer"&gt;AutoMaintainer&lt;/a&gt; fleet runs 24/7. It opens PRs, rebases them, and tries to merge them automatically. About 80% get merged without human help. The remaining 20% escalate to a human-in-the-loop queue — merge conflicts the rebaser can't resolve, PRs that need a judgment call, duplicates that need triage.&lt;/p&gt;

&lt;p&gt;Last week I checked the queue. &lt;strong&gt;20 PRs waiting for my decision.&lt;/strong&gt; The oldest had been stuck for 703 hours — 29 days. Some were duplicates of each other. Some were trivial doc fixes blocked by context drift. All needed me to type one of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CEO: approve&lt;/code&gt; — merge as-is&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CEO: approve rebase&lt;/code&gt; — try to resolve conflicts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CEO: deny&lt;/code&gt; — close the PR&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CEO: split into &amp;lt;description&amp;gt;&lt;/code&gt; — break into smaller PRs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was the bottleneck. Not because the decisions are hard — most are obvious — but because I don't check the queue every day, and 20 PRs pile up fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: an AI persona that replaces me
&lt;/h2&gt;

&lt;p&gt;I already had the infrastructure. My &lt;a href="https://github.com/javimosch/fleet-cli" rel="noopener noreferrer"&gt;fleet-cli&lt;/a&gt; engine runs scheduled loops on a Proxmox container. The am-fleet HITL system already watches for replies on GitHub issues and applies decisions automatically. The only missing piece was someone to actually make the decisions.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Felipe&lt;/strong&gt; — a fleet persona that runs once a day, reads every stuck PR, and posts a CEO decision as a comment on the GitHub issue. The existing &lt;code&gt;am-hitl-resume&lt;/code&gt; script picks up the reply within 5 minutes and applies it.&lt;/p&gt;

&lt;p&gt;The whole loop is ~200 lines of bash.&lt;/p&gt;

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

&lt;p&gt;Once a day at 09:00 UTC, a systemd timer fires &lt;code&gt;fleet-felipe-decide.service&lt;/code&gt; on rbm21. The script does five things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Fetch the queue.&lt;/strong&gt; &lt;code&gt;gh issue list --repo javimosch/am-fleet --label mago:hitl --state open&lt;/code&gt; — same command I'd run manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Read each PR.&lt;/strong&gt; For every issue, Felipe extracts the repo and PR number, fetches the diff (first 500 lines), CI status, and merge state via &lt;code&gt;gh pr view&lt;/code&gt; and &lt;code&gt;gh pr diff&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Ask the LLM.&lt;/strong&gt; A structured prompt goes to &lt;code&gt;devin --model glm-5-2 --print&lt;/code&gt; — GLM-5.2 High, which is &lt;strong&gt;free on Devin&lt;/strong&gt;. The prompt includes the PR size, file list, CI status, the full diff, and the HITL issue body. The rules are explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. CEO: approve       — if PR &amp;lt;200 lines, CI passes, changes look safe
2. CEO: deny           — if stale &amp;gt;7 days, duplicate, or broken
3. CEO: approve rebase — if conflicts but valuable and &amp;lt;100 lines
4. CEO: split into     — if &amp;gt;500 lines mixing unrelated changes
5. CEO: &amp;lt;custom&amp;gt;       — anything else
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Post the decision.&lt;/strong&gt; Felipe parses the LLM response for a line starting with &lt;code&gt;CEO:&lt;/code&gt; and posts it as a comment on the GitHub issue, signed &lt;em&gt;"Felipe (AI CEO)"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The existing machinery takes over.&lt;/strong&gt; &lt;code&gt;am-hitl-resume.sh&lt;/code&gt; runs every 5 minutes, detects the reply, parses the decision, and applies it — approving the PR, closing it, or requesting a rebase. The HITL issue is closed. The loop is complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first run: 20 PRs in 5 minutes
&lt;/h2&gt;

&lt;p&gt;I deployed Felipe and triggered a manual run. It processed all 20 HITL issues in about 5 minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;14 × approve rebase&lt;/strong&gt; — small PRs with trivial conflicts worth retrying&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4 × deny&lt;/strong&gt; — stale conflicts older than 7 days, too large to rebase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 × split&lt;/strong&gt; — 350+ line PRs mixing unrelated concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The decisions were good. Felipe caught that &lt;code&gt;supercli#370&lt;/code&gt; was a small doc-only change (24 lines, install instructions) and approved a rebase. It caught that &lt;code&gt;scan-and-fill#7&lt;/code&gt; was 352 lines mixing three unrelated features (amount parsing, AI caching, async refactor) and asked for a split. It denied &lt;code&gt;superinsights#29&lt;/code&gt; because it had been conflicting for 8 days and the conflicts spanned multiple files.&lt;/p&gt;

&lt;p&gt;Within 10 minutes, &lt;code&gt;am-hitl-resume&lt;/code&gt; had processed the first reply — approved PR #568, labeled it &lt;code&gt;human-approved&lt;/code&gt;, and closed the HITL issue. The rebaser picked it up on the next cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost: $0
&lt;/h2&gt;

&lt;p&gt;Felipe uses &lt;strong&gt;GLM-5.2 High&lt;/strong&gt;, which is free on &lt;a href="https://devin.ai" rel="noopener noreferrer"&gt;Devin&lt;/a&gt;. Each PR review sends an ~8K token prompt (diff + metadata + rules). For 20 PRs, that's ~160K tokens in, ~5K tokens out. On a paid model like Claude Sonnet 5 Low, that would cost ~$0.40. On GLM-5.2, it costs nothing.&lt;/p&gt;

&lt;p&gt;The quality is good enough for this task. PR review decisions are bounded — there are only 5 possible actions, the rules are explicit, and the LLM just needs to read a diff and pick one. GLM-5.2 handles this without trouble. I wouldn't trust it with open-ended architecture decisions, but for "should I rebase this 24-line doc fix?" it's more than sufficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that almost killed it
&lt;/h2&gt;

&lt;p&gt;The first version processed 1 PR and stopped. The cause was a classic bash gotcha: &lt;strong&gt;commands inside a &lt;code&gt;while read&lt;/code&gt; loop consume stdin from the loop's file redirect&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The loop was &lt;code&gt;while IFS= read -r issue; do ... done &amp;lt; issues.jsonl&lt;/code&gt;. Inside the loop, &lt;code&gt;gh pr diff&lt;/code&gt; and &lt;code&gt;gh issue comment&lt;/code&gt; were reading from stdin — which was the JSONL file. They ate the remaining lines, so &lt;code&gt;read&lt;/code&gt; got EOF on the next iteration.&lt;/p&gt;

&lt;p&gt;The fix: &lt;code&gt;&amp;lt;/dev/null&lt;/code&gt; on every command inside the loop. One redirect, three commands, 20 PRs processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before (broken — gh eats the loop's stdin)&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;diff &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pr_num&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--repo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$repo&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null
gh issue comment &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$issue_num&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--repo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FLEET_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# After (fixed — /dev/null on every subcommand)&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;diff &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pr_num&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--repo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$repo&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;/dev/null
gh issue comment &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$issue_num&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--repo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FLEET_REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;lt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;The pattern here is bigger than PR review. It's &lt;strong&gt;delegation to an AI persona&lt;/strong&gt;. Felipe has a name, a role (CEO), a decision framework, and a schedule. It doesn't replace me — I can override any decision by replying on the GitHub issue. But it handles the 90% of decisions that are obvious, so I only see the 10% that actually need human judgment.&lt;/p&gt;

&lt;p&gt;The architecture is composable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;fleet-cli&lt;/strong&gt; provides the scheduling and execution framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;am-fleet&lt;/strong&gt; provides the HITL queue and decision-application machinery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Devin + GLM-5.2&lt;/strong&gt; provides the LLM inference, free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Issues&lt;/strong&gt; provides the communication channel — Felipe posts a comment, the resume script reads it, no custom API needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No new infrastructure. No new database. No new API. Just a 200-line bash script that bridges three existing systems.&lt;/p&gt;

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

&lt;p&gt;Felipe is part of my &lt;a href="https://github.com/javimosch/fleets" rel="noopener noreferrer"&gt;private fleets repository&lt;/a&gt;. The &lt;a href="https://github.com/javimosch/fleet-cli" rel="noopener noreferrer"&gt;fleet-cli engine&lt;/a&gt; is open source. The am-fleet HITL scripts are on &lt;a href="https://github.com/javimosch/am-fleet" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have a fleet-cli setup and want to add Felipe, the loop is straightforward: fetch your HITL queue, read each PR, ask an LLM for a decision, post it back. The hardest part is the bash stdin bug. Now you know about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next in this series:&lt;/strong&gt; &lt;a href="https://blog.intrane.fr/the-ratchet-how-my-ai-fleet-merges-its-own-prs" rel="noopener noreferrer"&gt;The Ratchet&lt;/a&gt; — how the AI merger self-unblocks 80% of PRs before escalating to Felipe.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>memgraph v1.9.1: a 4-question gate before every AI memory</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Wed, 02 Sep 2026 23:14:09 +0000</pubDate>
      <link>https://dev.to/javimosch/memgraph-v191-a-4-question-gate-before-every-ai-memory-3hph</link>
      <guid>https://dev.to/javimosch/memgraph-v191-a-4-question-gate-before-every-ai-memory-3hph</guid>
      <description>&lt;p&gt;memgraph v1.9.1 ships a small but consequential change: a content discipline section now lives inside the guide, and a 4-question gate runs before every &lt;code&gt;memgraph remember&lt;/code&gt;. The headline is "memorize what code cannot tell you" — if the answer to a question is already in the source, the repo, or the commit log, it doesn't belong in memory.&lt;/p&gt;

&lt;p&gt;The motivation is straightforward. Memory stores that duplicate what the codebase already says get noisy fast, and noisy memory is worse than no memory because agents trust it. This release pushes the filter upstream: don't write it down if you could just read it from the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content discipline section in the guide.&lt;/strong&gt; Both the JSON and human-readable guide output now include a content discipline section, so any agent reading the guide picks up the rule set without an extra fetch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4-question gate before every remember.&lt;/strong&gt; Before &lt;code&gt;memgraph remember&lt;/code&gt; commits anything, four questions check whether the content is something code itself can tell you. If it is, the memory is rejected. This keeps the memory store focused on non-obvious knowledge — decisions, caveats, deployment quirks — rather than duplicating what's already in the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-repo skill.&lt;/strong&gt; The full skill lives at the path below, versioned with the repo and discoverable by other agents working in the same codebase:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.agents/skills/memgraph-content-discipline/SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub link in guide output.&lt;/strong&gt; The guide now links to the full skill on GitHub, so a human reading the guide output can jump straight to the source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.gitignore fix.&lt;/strong&gt; A previous .gitignore rule was matching the skill directory as binary, which would have excluded it from the repo. Fixed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The diff is 4 files changed, +152/-1. Small release, but it changes the default behavior of every &lt;code&gt;remember&lt;/code&gt; call going forward — the gate runs unless you explicitly bypass it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/javimosch/memgraph" rel="noopener noreferrer"&gt;https://github.com/javimosch/memgraph&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>testing</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>machin v0.133.0: select on Windows, concurrency CI runs there</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 14 Aug 2026 00:06:13 +0000</pubDate>
      <link>https://dev.to/javimosch/machin-v01330-select-on-windows-concurrency-ci-runs-there-16a5</link>
      <guid>https://dev.to/javimosch/machin-v01330-select-on-windows-concurrency-ci-runs-there-16a5</guid>
      <description>&lt;p&gt;machin v0.133.0 is out. The headline change is small in diff size but fixes a real gap: &lt;code&gt;select&lt;/code&gt; now works on the windows target, and the concurrency test suite actually runs in CI on Windows instead of being quietly skipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;Two user-visible changes shipped in this release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;select&lt;/code&gt; works on the windows target.&lt;/strong&gt; Previously &lt;code&gt;select&lt;/code&gt; was not supported when building for Windows. That meant a core concurrency primitive was effectively off-limits for anyone targeting that platform, and any code relying on it would fail to build or behave incorrectly there. With v0.133.0, &lt;code&gt;select&lt;/code&gt; is available on the windows target like it is elsewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI now runs the concurrency suite on Windows.&lt;/strong&gt; Closing #517 and #619, the concurrency tests are no longer excluded from the Windows CI leg. This is the natural complement to the first change: now that &lt;code&gt;select&lt;/code&gt; works there, the existing concurrency tests can actually execute and guard against regressions on that target.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The diff itself is deliberately small: 4 files changed, +37/-3, touching &lt;code&gt;CHANGELOG.md&lt;/code&gt;, &lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;SPEC.md&lt;/code&gt;, and &lt;code&gt;guide.go&lt;/code&gt;. No new dependencies, no API surface added beyond making &lt;code&gt;select&lt;/code&gt; available where it already existed on other targets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;A language or runtime that supports a concurrency primitive on some targets but not others creates a subtle trap: code that works fine on the developer's machine can fail on a different target, and if CI doesn't run the relevant tests on that target, the failure only surfaces downstream. This release closes both halves of that trap for &lt;code&gt;select&lt;/code&gt; on Windows — the primitive is implemented, and the tests that exercise it (and the broader concurrency model) now run on every CI leg where the target is built.&lt;/p&gt;

&lt;p&gt;If you've been avoiding &lt;code&gt;select&lt;/code&gt; in machin because you needed Windows support, that constraint is gone as of v0.133.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code example
&lt;/h2&gt;

&lt;p&gt;A minimal &lt;code&gt;select&lt;/code&gt; over two channels, now valid on the windows target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing new about the syntax — the change is that this now compiles and runs correctly when the target is Windows, and the concurrency tests that cover patterns like this execute in CI on that target.&lt;/p&gt;

&lt;p&gt;Release commit: &lt;code&gt;510ff9f8608c952984f0144a8ebd75cdf99bc40e&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Full changelog and source: &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;https://github.com/javimosch/machin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>testing</category>
      <category>go</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
