<?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.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>
    <item>
      <title>machin: make([]T, n) and make([]T, len, cap) for slices</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 14 Aug 2026 00:06:10 +0000</pubDate>
      <link>https://dev.to/javimosch/machin-maket-n-and-maket-len-cap-for-slices-5400</link>
      <guid>https://dev.to/javimosch/machin-maket-n-and-maket-len-cap-for-slices-5400</guid>
      <description>&lt;p&gt;A new machin release shipped, headlined by proper support for &lt;code&gt;make([]T, n)&lt;/code&gt; and &lt;code&gt;make([]T, len, cap)&lt;/code&gt;. The slice implementation, AST, and codegen all learned the two- and three-argument forms, so you can preallocate a slice with an explicit length and an optional capacity the way you would in Go.&lt;/p&gt;

&lt;p&gt;Alongside that, the router got a semantics pass and the coverage tooling got some rough edges filed off. The Windows target also picked up two C libraries that had been missing.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;make([]T, n)&lt;/code&gt; and &lt;code&gt;make([]T, len, cap)&lt;/code&gt; now work end to end (#584, #617). Touched &lt;code&gt;SPEC.md&lt;/code&gt;, &lt;code&gt;alias.go&lt;/code&gt;, &lt;code&gt;ast.go&lt;/code&gt;, &lt;code&gt;codegen.go&lt;/code&gt;, and &lt;code&gt;docs/LANGUAGE.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Router semantics: unknown paths are now distinguishable. &lt;code&gt;navigate&lt;/code&gt; returns &lt;code&gt;-1&lt;/code&gt; for unknown paths and the route table resets on init (#606, shipped as v0.130.0).&lt;/li&gt;
&lt;li&gt;The upper bound of &lt;code&gt;navigate&lt;/code&gt; is now guarded as well, and the new semantics are documented (#609).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;machin test --cover&lt;/code&gt; is now advertised in the usage output and header (#615).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--cover&lt;/code&gt; JSON emits empty uncovered arrays instead of &lt;code&gt;null&lt;/code&gt; (#616), so consumers don't have to special-case missing keys.&lt;/li&gt;
&lt;li&gt;v0.129.0: SQLite on the Windows target, verified by running it (#605).&lt;/li&gt;
&lt;li&gt;v0.131.0: zlib on the Windows target, verified by running it (#613).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A concrete example of the new slice allocation:&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="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first form gives you a zero-length, 4096-capacity buffer for appending; the second gives you a length-&lt;code&gt;n&lt;/code&gt; slice ready to index and assign. Both now go through the same codegen path as the rest of the slice machinery.&lt;/p&gt;

&lt;p&gt;Nine files changed in this release (+292/-2), mostly in the language core and docs.&lt;/p&gt;

&lt;p&gt;Repo: &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>Your homelab behind CGNAT is now reachable for free</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Tue, 11 Aug 2026 20:31:02 +0000</pubDate>
      <link>https://dev.to/javimosch/your-homelab-behind-cgnat-is-now-reachable-for-free-54lg</link>
      <guid>https://dev.to/javimosch/your-homelab-behind-cgnat-is-now-reachable-for-free-54lg</guid>
      <description>&lt;p&gt;I built &lt;a href="https://github.com/javimosch/remotecmd-cli" rel="noopener noreferrer"&gt;rcmd&lt;/a&gt; — a relay-based remote execution tool. Your server connects out to a relay; you connect to the same relay from your laptop; the relay routes commands between you. No SSH keys, no open ports, no VPN. It works behind NAT, CGNAT, corporate firewalls — anywhere that allows outbound HTTPS, which is everywhere.&lt;/p&gt;

&lt;p&gt;Until now it was self-hosted-only: you run the relay on your own VPS, you run the daemon on your targets, you connect from your laptop. That works, but it has a gap. If you're behind CGNAT — which most home ISPs do now — you can't host the relay at home either. You need a VPS for the relay. And now you're paying €4-6/month just to forward traffic.&lt;/p&gt;

&lt;p&gt;As of today there's a free hosted relay. Three servers, no credit card, no VPS required.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three plans
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free (hosted)&lt;/strong&gt; — 3 servers on &lt;code&gt;rcmd.intrane.fr&lt;/code&gt;, no credit card. New.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro (€5/mo)&lt;/strong&gt; — unlimited servers, plus cron scheduling, port forwarding, team access, webhooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted (free, OSS)&lt;/strong&gt; — run your own relay, unlimited everything, MIT licensed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The free tier is the one that matters if you're homelabbing. Three servers covers most home setups — a NAS, a Home Assistant, a build box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set it up in 60 seconds
&lt;/h2&gt;

&lt;p&gt;On your home server (the one behind CGNAT):&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;-sSL&lt;/span&gt; https://rcmd.intrane.fr/install.sh | sh
rcmd signup &lt;span class="nt"&gt;--free&lt;/span&gt; &lt;span class="nt"&gt;--email&lt;/span&gt; you@example.com
rcmd set-relay &lt;span class="nt"&gt;--url&lt;/span&gt; wss://rcmd.intrane.fr &lt;span class="nt"&gt;--name&lt;/span&gt; homeserver
rcmd daemon start &lt;span class="nt"&gt;-daemon&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On your laptop, anywhere in the world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd login &amp;lt;your-token&amp;gt;
rcmd &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; homeserver &lt;span class="nt"&gt;--cmd&lt;/span&gt; &lt;span class="s2"&gt;"uptime"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Your home server is reachable from anywhere. The daemon connected out; your laptop connected to the same relay; the relay routed the command.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you actually get
&lt;/h2&gt;

&lt;p&gt;This isn't just "run a command remotely." The relay model gives you a few things SSH doesn't:&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast file transfer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; homeserver &lt;span class="nt"&gt;--src&lt;/span&gt; ./config.yaml &lt;span class="nt"&gt;--dst&lt;/span&gt; /etc/app/config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Files stream through the relay in 2 MiB chunks with adaptive gzip and parallel streams. I benchmarked it &lt;a href="https://blog.intrane.fr/remotecmd-parallel-streams-faster-than-scp" rel="noopener noreferrer"&gt;faster than scp&lt;/a&gt; over high-RTT links — the relay's async write queue forwards chunk N to the target while the client sends chunk N+1, so the pipeline stays full. Directories are auto-tarred. No base64, no buffering the whole file in memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Port forwarding (tunnels)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd tunnel &lt;span class="nt"&gt;--target&lt;/span&gt; db &lt;span class="nt"&gt;--local&lt;/span&gt; 5432 &lt;span class="nt"&gt;--remote&lt;/span&gt; 127.0.0.1:5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replaces &lt;code&gt;ssh -L&lt;/code&gt;. Forward a local port to a remote address through the relay. Reach that database behind NAT without a VPN or a bastion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-target fan-out
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--targets&lt;/span&gt; nas,homeassistant,buildbox &lt;span class="nt"&gt;--cmd&lt;/span&gt; &lt;span class="s2"&gt;"df -h"&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command across every server. Results back as JSON — one per target, with stdout, stderr, exit code, and duration. No parsing SSH output, no parallel-SSH wrapper.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI-agent native
&lt;/h3&gt;

&lt;p&gt;Every command returns structured JSON. Deterministic timeouts. No parsing, no guessing, no wasted tokens. If you're building agents with Claude Code, Cursor, or Devin, you give the agent a token instead of an SSH key. I &lt;a href="https://blog.intrane.fr/stop-giving-ai-agents-your-ssh-keys" rel="noopener noreferrer"&gt;wrote about the security argument separately&lt;/a&gt; — but the short version is: an SSH key is a permanent credential with no scoping. A token is a revocable credential with per-target permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just self-host?
&lt;/h2&gt;

&lt;p&gt;You can. The &lt;a href="https://github.com/javimosch/remotecmd-cli/blob/main/docs/self-hosting.md" rel="noopener noreferrer"&gt;self-hosted relay&lt;/a&gt; is free and MIT licensed, with unlimited targets and all features unlocked. But self-hosting means you need a machine with a public IP to run it on — which, if you're behind CGNAT, is exactly the problem you're solving. You'd need a VPS for the relay, and now you're back to paying for a VPS.&lt;/p&gt;

&lt;p&gt;The free hosted tier breaks that loop. I run the relay. You use it for free. Your home servers connect out to it. You reach them from anywhere. No VPS for you, no CGNAT problem, no credit card.&lt;/p&gt;

&lt;p&gt;If you outgrow 3 servers — you add a fourth machine, or you want cron scheduling for backups, or you want to share access with a teammate — Pro is €5/month and removes the limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the relay can and can't see
&lt;/h2&gt;

&lt;p&gt;Fair question: if all my traffic goes through a relay, what can the operator see?&lt;/p&gt;

&lt;p&gt;Commands and output pass through the relay, but they're not stored — the relay routes frames in memory and drops them when delivered. The relay authenticates both sides with tokens; it doesn't have your SSH keys because there are no SSH keys. If that's still too much trust, self-host the relay and keep everything on your own infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Homelabbers behind CGNAT&lt;/strong&gt; who want to reach their machines without a VPN mesh or a VPS tunnel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;People with 2-3 VPSes&lt;/strong&gt; tired of maintaining SSH config, key rotation, and bastion setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI agent builders&lt;/strong&gt; who need their agent to run commands on remote machines without SSH keys.&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;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://rcmd.intrane.fr/install.sh | sh
rcmd signup &lt;span class="nt"&gt;--free&lt;/span&gt; &lt;span class="nt"&gt;--email&lt;/span&gt; you@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three servers, no credit card, no VPS, no CGNAT workaround. Landing page: &lt;a href="https://rcmd.intrane.fr?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=homelab-cgnat?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=homelab-cgnat" rel="noopener noreferrer"&gt;rcmd.intrane.fr&lt;/a&gt;. Source: &lt;a href="https://github.com/javimosch/remotecmd-cli" rel="noopener noreferrer"&gt;github.com/javimosch/remotecmd-cli&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Previously: &lt;a href="https://blog.intrane.fr/stop-giving-ai-agents-your-ssh-keys" rel="noopener noreferrer"&gt;Stop Giving AI Agents Your SSH Keys&lt;/a&gt; — the security argument for the relay model. &lt;a href="https://blog.intrane.fr/remotecmd-parallel-streams-faster-than-scp" rel="noopener noreferrer"&gt;remotecmd parallel streams, faster than scp&lt;/a&gt; — the file transfer benchmark.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>homelab</category>
      <category>selfhosting</category>
      <category>devops</category>
      <category>networking</category>
    </item>
    <item>
      <title>I benchmarked my language against Rust and Zig, and deleted my best number</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 07 Aug 2026 12:36:17 +0000</pubDate>
      <link>https://dev.to/javimosch/i-benchmarked-my-language-against-rust-and-zig-and-deleted-my-best-number-a9h</link>
      <guid>https://dev.to/javimosch/i-benchmarked-my-language-against-rust-and-zig-and-deleted-my-best-number-a9h</guid>
      <description>&lt;p&gt;I benchmarked my language against Rust and Zig, and deleted my best number&lt;/p&gt;

&lt;p&gt;I have been building &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;machin&lt;/a&gt; for a while — a Go-flavored, type-inferred language that compiles through C to a single native binary. It has grown a lot recently, and I wanted to answer the obvious question honestly: &lt;strong&gt;does it beat Rust and Zig at anything?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It does, at two things, decisively. But the first thing I found was not a win. It was my own benchmark quietly lying to me, and the number it was lying about was the best one I had.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benchmark was measuring the order I ran things in
&lt;/h2&gt;

&lt;p&gt;machin's repo has had a &lt;code&gt;bench/native-speed&lt;/code&gt; suite for months: four compute kernels — recursive fib, a mandelbrot, a sieve, a big integer loop — written in machin, Rust and Zig, producing byte-identical output, so the timing compares the same computation three ways. The published result claimed machin won the integer loop &lt;strong&gt;by 20-25%&lt;/strong&gt;. That claim also shipped inside &lt;code&gt;machin guide&lt;/code&gt;, which is what every coding agent reads to learn the language.&lt;/p&gt;

&lt;p&gt;When I re-ran it, the margin was gone. Not shrunk — gone. So I read the harness instead of the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kernels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;machin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rust&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;    &lt;span class="c1"&gt;# all 5 machin, THEN all 5 rust, THEN all 5 zig
&lt;/span&gt;            &lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It ran every sample of one language before starting the next. On a laptop that heats up and down-clocks during a three-second kernel, that does not measure the languages. It measures &lt;em&gt;who had the misfortune of running last&lt;/em&gt;. Zig always went last. Zig always looked slowest.&lt;/p&gt;

&lt;p&gt;The fix is four lines — interleave the rounds, rotate who starts each one. Here is what my headline number did:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;intsum 10^9      before (blocked)     after (interleaved)
machin              2832 ms                3079.7 ms
rust                3764 ms                3223.8 ms
zig                 3556 ms                3189.7 ms
                 "machin +20-25%"        machin +3% = a TIE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 20-25% win became a tie. I deleted the claim from the README and from &lt;code&gt;machin guide&lt;/code&gt;. The harness now also refuses to declare a winner inside a 3% band, because the worst run-to-run spread I measured was 41% of the min sample. Calling winners inside that is how benchmarks start lying in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what does machin actually win?
&lt;/h2&gt;

&lt;p&gt;Two things, and neither is raw speed. On the four kernels machin wins one clearly (recursion, 26% faster than both), ties two, loses one. Same tier as Rust and Zig — it compiles to C, so it runs about as fast as C, and so do they.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. It tells you about the bug before you run it
&lt;/h3&gt;

&lt;p&gt;A program that waits for a value that can never arrive. In machin it's a receive on a channel nothing sends to; in Rust &lt;code&gt;rx.recv()&lt;/code&gt; with the sender alive; in Zig &lt;code&gt;sem_wait&lt;/code&gt; on a semaphore nobody posts. Same program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;machin   DL001 at COMPILE time: "receive on channel `ch` that is never
         sent to or closed - a guaranteed deadlock"
         ...and at runtime, exit 2 with the wait-cycle:
           fatal: deadlock - all 1 goroutine(s) blocked
             goroutine 0   waiting to receive on channel #0

rust     compiles clean, no diagnostic -&amp;gt; HANGS FOREVER (killed at 5s)
zig      compiles clean, no diagnostic -&amp;gt; HANGS FOREVER (killed at 5s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This deserves precision, because it's easy to overclaim. Rust's type system prevents &lt;strong&gt;data races&lt;/strong&gt;. It has never claimed to prevent &lt;strong&gt;deadlocks&lt;/strong&gt;, and that &lt;code&gt;recv()&lt;/code&gt; is idiomatic, &lt;code&gt;unsafe&lt;/code&gt;-free, well-typed Rust. Zig doesn't attempt either.&lt;/p&gt;

&lt;p&gt;Same for an out-of-range index: &lt;code&gt;machin falsify&lt;/code&gt; enumerates small concrete inputs and hands back one that breaks the function — before the program runs, on code whose only call site is in range. &lt;code&gt;rustc&lt;/code&gt; and &lt;code&gt;zig&lt;/code&gt; say nothing.&lt;/p&gt;

&lt;p&gt;Neither analysis proves absence, and I don't want to imply otherwise. &lt;code&gt;falsify&lt;/code&gt; is unsound-complete: every counterexample it reports is real, but a clean result means "no bug within the bounds", never "correct". &lt;code&gt;DL001&lt;/code&gt; is the opposite trade — sound and false-positive-free, so it only fires when it can &lt;em&gt;prove&lt;/em&gt; a channel is never fed, which means a clean result isn't a proof of deadlock-freedom either. "machin found nothing" is a much weaker statement than "machin found this bug, here's the input".&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Binary size
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stripped, both dynamically linked against system libc:

  machin      14 kB
  rust       335 kB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No std runtime to link — machin's output is C, and C's runtime is already on the machine. Note the comparison I did &lt;em&gt;not&lt;/em&gt; make: unstripped it's 17 kB vs 4291 kB, about 250x. That number is bigger and worse, because it mostly measures how much debug info each toolchain leaves in.&lt;/p&gt;

&lt;p&gt;And here is the correction I owe that 24x, which I only caught by going back and asking what it actually measures. It compares each toolchain's &lt;strong&gt;fixed floor&lt;/strong&gt;, not how they scale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;program            machin        rust
hello world       14,544 B    343,568 B
fib(40)           14,544 B    335,472 B
a JSON+HTTP app   26,840 B          -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;machin's hello world and its fib are &lt;em&gt;byte-identical in size&lt;/em&gt;; Rust's differ by 2%. Neither number measures the program — both measure the baseline each toolchain links in, and real code adds real bytes to both. So the honest form is &lt;strong&gt;"Rust starts about 320 kB ahead"&lt;/strong&gt;, not "machin binaries are 24x smaller". The ratio shrinks as programs grow; the offset persists.&lt;/p&gt;

&lt;h2&gt;
  
  
  And what it loses
&lt;/h2&gt;

&lt;p&gt;A benchmark suite that only lists wins is marketing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build time: Rust wins.&lt;/strong&gt; Bare &lt;code&gt;rustc -C opt-level=3&lt;/code&gt; builds these kernels in ~57 ms; machin takes ~95-116 ms, because its number includes the &lt;code&gt;cc -O2&lt;/code&gt; backend run. I deliberately did not use &lt;code&gt;cargo&lt;/code&gt;, which would have charged Rust for lockfile resolution and made machin look good for a bad reason.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default runtime safety: Rust wins.&lt;/strong&gt; Given an out-of-range index, Rust traps (exit 101). machin's &lt;em&gt;default&lt;/em&gt; build prints a silent wrong &lt;code&gt;0&lt;/code&gt; and exits successfully — exactly like Zig's ReleaseFast, which read &lt;code&gt;281479271677952&lt;/code&gt; out of adjacent memory. Both need an opt-in to trap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fully static, Zig wins — by far more than I first reported.&lt;/strong&gt; I originally wrote "491 kB against machin's 940 kB", about 2x. That 491 kB came from Zig &lt;strong&gt;0.16.0&lt;/strong&gt;, which inflates it ~32x. On 0.15.2 the &lt;em&gt;fully static&lt;/em&gt; stripped binary is &lt;strong&gt;16 kB&lt;/strong&gt; — about the size of machin's &lt;em&gt;dynamic&lt;/em&gt; one, needing nothing on the target — and &lt;strong&gt;~60x smaller than machin's own &lt;code&gt;--static&lt;/code&gt; build&lt;/strong&gt;. The size win in this post is over Rust, not over Zig.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That second one matters enough to repeat, because I got it wrong first. My initial version compared machin &lt;code&gt;--safe&lt;/code&gt; against Zig &lt;code&gt;ReleaseFast&lt;/code&gt; — machin's checked mode against Zig's unchecked one — and machin looked safe by default. It is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sieve: three months of a wrong explanation
&lt;/h2&gt;

&lt;p&gt;machin has always trailed on the sieve by ~1.4x, and the README explained it confidently: &lt;em&gt;"its slice indexing/layout is less optimal than a Rust Vec or a Zig slice."&lt;/em&gt; That was wrong, and nobody checked because the conclusion sounded plausible.&lt;/p&gt;

&lt;p&gt;Timing the phases took ten minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phase                              machin      rust
build the 10M array by append     70-83 ms   27-29 ms
the sieve loop itself              110 ms     111 ms   &amp;lt;- dead tie
the count loop                     5-7 ms       3 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Slice indexing ties Rust &lt;em&gt;exactly&lt;/em&gt;. The entire gap is &lt;code&gt;append&lt;/code&gt; growing the array: machin's arenas free nothing mid-life, so growing a slice can only allocate a fresh block and memcpy into it, ~21 times, never releasing the old buffers. &lt;code&gt;Vec::push&lt;/code&gt; hands the block to &lt;code&gt;realloc&lt;/code&gt;, and glibc extends it in place via &lt;code&gt;mremap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I wrote the obvious fix: when the block being grown is the arena's most recent allocation, hand it straight to &lt;code&gt;realloc&lt;/code&gt;. Then I checked one thing before shipping — whether MFL slices share backing storage:&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="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;          &lt;span class="c"&gt;// b[0] changes when a[0] does -&amp;gt; they SHARE&lt;/span&gt;
&lt;span class="n"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c"&gt;// params share too&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They do. Today, when &lt;code&gt;append&lt;/code&gt; abandons a block, every existing alias keeps pointing at it and keeps reading valid memory, because the arena never frees. With in-place growth those aliases become &lt;strong&gt;use-after-free&lt;/strong&gt; the moment the block moves. I had written a 45 ms speedup that trades a benchmark number for silent dangling reads — in a language whose entire pitch is catching that class of bug.&lt;/p&gt;

&lt;p&gt;I threw it away and filed &lt;a href="https://github.com/javimosch/machin/issues/578" rel="noopener noreferrer"&gt;issue #578&lt;/a&gt; with the directions that could actually be sound. &lt;strong&gt;That fix has since landed&lt;/strong&gt; — see the update at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the claim actually is
&lt;/h2&gt;

&lt;p&gt;Not "machin is faster than Rust" — same tier, and it loses a kernel. Not "machin is safer than Rust" — Rust traps by default and machin does not.&lt;/p&gt;

&lt;p&gt;The claim is &lt;strong&gt;machin tells you earlier&lt;/strong&gt;. A deadlock that Rust and Zig discover as a hung process in production, machin reports at compile time with the wait-cycle. An out-of-range index neither mentions, machin hands you with a concrete failing input. That's a real difference, worth real debugging time, and it's a &lt;em&gt;different&lt;/em&gt; claim from Rust's rather than a bigger one.&lt;/p&gt;

&lt;p&gt;Every number is reproducible — sources for all three languages, the harnesses, and a &lt;code&gt;run.sh&lt;/code&gt; per benchmark. Start at &lt;a href="https://github.com/javimosch/machin/blob/main/docs/BENCHMARKS.md" rel="noopener noreferrer"&gt;docs/BENCHMARKS.md&lt;/a&gt;, which indexes all seven benchmarks and states the losses next to the wins.&lt;/p&gt;

&lt;p&gt;If you re-run them and get different numbers, I'd genuinely like to know. That's rather the point of shipping the harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postscript: I ran it all on a second machine
&lt;/h2&gt;

&lt;p&gt;Every number above came from one laptop with 41% worst-case run-to-run spread, and I'd told readers that "the ratios are the portable result" without ever testing that. So I wired the suite into CI and ran it on a GitHub runner — AMD EPYC, different compilers, much quieter (15% spread).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;verdicts&lt;/strong&gt; are portable. machin still wins recursion (26% → 28%), mandelbrot and intsum are still ties, the sieve was still a loss &lt;em&gt;at the time of writing&lt;/em&gt; (it has since been fixed — see the update below), and every compile-time result (&lt;code&gt;DL001&lt;/code&gt;, &lt;code&gt;FALS001&lt;/code&gt;, who hangs, who traps) reproduces exactly.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;precise ratios&lt;/strong&gt; are not. The sieve gap moved from 1.46x to 1.32x — a ~10% swing, which fits its cause: it's &lt;code&gt;append&lt;/code&gt; faulting in fresh pages, the most memory-sensitive thing in the suite, and the EPYC has a better memory subsystem.&lt;/p&gt;

&lt;p&gt;And it caught the Zig size error above, which is the entire reason for running it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Update: the sieve now ties Rust
&lt;/h2&gt;

&lt;p&gt;Everything above described the sieve as machin's remaining loss, and explained it correctly as &lt;code&gt;append&lt;/code&gt; rather than indexing. That gap is now closed, and it's worth saying how, because the interesting part isn't the speedup.&lt;/p&gt;

&lt;p&gt;The unsound version — hand the arena's newest block to &lt;code&gt;realloc&lt;/code&gt; — was the easy 45 ms. Making it safe meant answering one question per slice: &lt;em&gt;does any other live reference observe this backing array?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The design decision that mattered was the failure direction.&lt;/strong&gt; The tempting implementation is a dynamic &lt;code&gt;shared&lt;/code&gt; bit on the slice header, set wherever the compiler copies one. Less code — but it &lt;strong&gt;fails open&lt;/strong&gt;: a copy site nobody thought of leaves an alias unmarked, and an unmarked alias is silent memory corruption. So instead: a static whitelist where every operation on a candidate must be a form that provably cannot leak a reference, and &lt;strong&gt;anything unrecognised refuses the slice&lt;/strong&gt;. The cost of a case nobody thought of becomes a missed optimization instead of a dangling pointer.&lt;/p&gt;

&lt;p&gt;I shipped that analysis first as a report — &lt;code&gt;machin alias&lt;/code&gt; — that changed no generated code at all. Which is how I found out my first version was useless:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;module&lt;/th&gt;
&lt;th&gt;flow-insensitive&lt;/th&gt;
&lt;th&gt;flow-sensitive&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;bson.src&lt;/td&gt;
&lt;td&gt;~0&lt;/td&gt;
&lt;td&gt;2 of 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;xml.src&lt;/td&gt;
&lt;td&gt;~0&lt;/td&gt;
&lt;td&gt;5 of 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reactive.src&lt;/td&gt;
&lt;td&gt;~0&lt;/td&gt;
&lt;td&gt;3 of 10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It was sound, and it fired on almost nothing real. "Build it, then use it" is the dominant shape — append in a loop, then hand the finished slice to a helper — and that aliasing use happens &lt;em&gt;after&lt;/em&gt; the last append, where it cannot observe a moved array. Had I gone straight to codegen I'd have shipped something that optimized my own benchmark and essentially nothing else.&lt;/p&gt;

&lt;p&gt;Then the net, before the thing it catches: seven programs that keep a live alias across an append, run under AddressSanitizer in CI. I verified it catches the bug by re-applying the unsound version and watching it go red — rather than assuming a green suite meant anything.&lt;/p&gt;

&lt;p&gt;Only then the codegen. Two guards the static proof can't express: growth is attempted only on the arena's most recent block, and the &lt;code&gt;substr&lt;/code&gt; length cache is invalidated on that path, because it keys on pointer identity and &lt;code&gt;realloc&lt;/code&gt; hands an address back to the allocator. Missing that second one would have been a silent wrong-length bug in &lt;code&gt;substr()&lt;/code&gt; — about as far from &lt;code&gt;append&lt;/code&gt; as a bug can land.&lt;/p&gt;

&lt;p&gt;Measured on a CI runner rather than my laptop (which was at 58-68% run-to-run noise by then), normalized against Rust because the runner itself drifted ~15% between sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              machin      rust       zig    machin/rust
  before      96.7ms    87.7ms    73.0ms       1.10x
  after      101.9ms   100.6ms    86.0ms       1.01x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The sieve ties Rust.&lt;/strong&gt; It does &lt;em&gt;not&lt;/em&gt; tie Zig, which is still ~1.19x faster on this kernel — down from 1.32x, but a real remaining gap, and I'd rather report it than round it into the headline.&lt;/p&gt;

&lt;p&gt;Shipped in v0.128.0.&lt;/p&gt;

</description>
      <category>database</category>
      <category>testing</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>My database claimed crash-safety. `kill -9` proved nothing.</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Wed, 29 Jul 2026 18:19:04 +0000</pubDate>
      <link>https://dev.to/javimosch/my-database-claimed-crash-safety-kill-9-proved-nothing-4bp</link>
      <guid>https://dev.to/javimosch/my-database-claimed-crash-safety-kill-9-proved-nothing-4bp</guid>
      <description>&lt;p&gt;I have a small document database called &lt;a href="https://github.com/javimosch/grange" rel="noopener noreferrer"&gt;grange&lt;/a&gt;. Its README said "crash-safe by construction", and there was a harness to back it up: kill the writer with &lt;code&gt;kill -9&lt;/code&gt; mid-flight, reopen, assert the database holds exactly a committed prefix. Five rounds, every build, green.&lt;/p&gt;

&lt;p&gt;That harness proves less than it looks like it proves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;kill -9&lt;/code&gt; actually tests
&lt;/h2&gt;

&lt;p&gt;When you &lt;code&gt;kill -9&lt;/code&gt; a process, the kernel reclaims it — but everything the process wrote with &lt;code&gt;write(2)&lt;/code&gt; is already in the page cache, and the kernel flushes it to disk afterwards on its own schedule. The data survives because the &lt;em&gt;operating system&lt;/em&gt; survived.&lt;/p&gt;

&lt;p&gt;A power cut is different. So is a kernel panic. There, the page cache goes with the machine, and anything not yet on the platter is gone.&lt;/p&gt;

&lt;p&gt;My database called &lt;code&gt;write_file&lt;/code&gt; and returned success. Nothing anywhere called &lt;code&gt;fsync&lt;/code&gt;. So a commit that had been acknowledged — the client got its &lt;code&gt;{"ok":true}&lt;/code&gt; — could vanish. The harness could never have caught it, because the failure mode it simulates is the one the page cache is immune to.&lt;/p&gt;

&lt;p&gt;The README even said so, in a line I'd stopped reading:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Durability is process-crash-exact (proven by &lt;code&gt;make crash&lt;/code&gt;), OS-crash best-effort.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence is true and completely insufficient. "Best-effort" is doing a lot of work there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two fsyncs, not one
&lt;/h2&gt;

&lt;p&gt;The fix is &lt;code&gt;fsync&lt;/code&gt;, and the part that's easy to get wrong is that one call isn't enough.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;write_file(path, data)
fsync(path)        // the file's CONTENTS are durable
fsync(dirname)     // the file's EXISTENCE is durable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a file is a modification of its &lt;em&gt;directory&lt;/em&gt;. You can fsync a file perfectly and still lose it after a crash, because the directory entry naming it never reached the disk. The second fsync is the one people skip.&lt;/p&gt;

&lt;p&gt;A directory has to be opened &lt;code&gt;O_RDONLY&lt;/code&gt; for this — opening it for writing fails with &lt;code&gt;EISDIR&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing something invisible
&lt;/h2&gt;

&lt;p&gt;Here's the awkward part: &lt;strong&gt;fsync is invisible to behavioural tests.&lt;/strong&gt; A build that silently dropped every fsync call would pass my entire test suite. Same answers, same recovery, same everything — right up until the power goes out.&lt;/p&gt;

&lt;p&gt;So the test doesn't check behaviour. It checks syscalls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;strace &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openat,fsync ./db put ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then asserts the ordering: the chunk is fsynced, &lt;em&gt;then&lt;/em&gt; its directory. And on the disk-resident path, that every data page is fsynced &lt;em&gt;before&lt;/em&gt; the manifest that references it — because "write the manifest last" is only meaningful if that ordering is real on the platter, and the kernel is free to reorder &lt;code&gt;write()&lt;/code&gt; calls on the way there.&lt;/p&gt;

&lt;p&gt;The third check is the one I'd encourage you to steal: the opt-out (&lt;code&gt;FSYNC=0&lt;/code&gt;) must issue &lt;strong&gt;zero&lt;/strong&gt; fsyncs. That doubles as the harness's own negative control. A test that can't fail is decoration, and a test asserting the presence of something invisible needs to prove it can detect the absence.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;Measured, on a commit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;single-document commits&lt;/td&gt;
&lt;td&gt;~1.9 ms each — about 31% slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a 10,000-document batch&lt;/td&gt;
&lt;td&gt;21 ms vs 23 ms — noise&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That shape is why it's on by default. A batch is one commit, so durability amortises to roughly nothing on the workload that actually moves volume. The per-commit case pays, and that's the honest price of the guarantee.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I still can't claim
&lt;/h2&gt;

&lt;p&gt;The device might be lying. Consumer drives with volatile write caches can acknowledge an &lt;code&gt;fsync&lt;/code&gt; that's still in flight, and no test running on that machine can tell. So the docs now say: fsync is called, the ordering is asserted, and whether your hardware honours it is not something this project can prove.&lt;/p&gt;

&lt;p&gt;That felt more useful than upgrading the marketing adjective.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general lesson
&lt;/h2&gt;

&lt;p&gt;The harness wasn't wrong. It tested a real failure mode, correctly, and it still passes. It just wasn't testing the failure mode the word "crash-safe" makes people imagine — and the gap between those two things sat in my README for months, written down, in a sentence I'd read so many times I stopped seeing it.&lt;/p&gt;

&lt;p&gt;If you have a durability claim, go and check what your test kills. &lt;code&gt;kill -9&lt;/code&gt; and "pull the plug" are not the same experiment.&lt;/p&gt;




&lt;p&gt;grange is MIT, a single static Linux binary, and usable either as a server or compiled into your own program: &lt;a href="https://github.com/javimosch/grange" rel="noopener noreferrer"&gt;github.com/javimosch/grange&lt;/a&gt;. v0.11.0 also brings ordered queries, keyset pagination and field projection.&lt;/p&gt;

</description>
      <category>database</category>
      <category>testing</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built a 100 KB git-like VCS that beats git on `add &amp;&amp; commit`</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Sun, 26 Jul 2026 05:42:26 +0000</pubDate>
      <link>https://dev.to/javimosch/i-built-a-100-kb-git-like-vcs-that-beats-git-on-add-commit-38h8</link>
      <guid>https://dev.to/javimosch/i-built-a-100-kb-git-like-vcs-that-beats-git-on-add-commit-38h8</guid>
      <description>&lt;p&gt;I love git. I also spend a lot of time automating things, and every time a script needs to snapshot some files I end up wrapping &lt;code&gt;git&lt;/code&gt; with brittle flags and parsing porcelain output. So I wrote &lt;strong&gt;lume&lt;/strong&gt;: a tiny, content-addressed version control system in &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;machin/MFL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;lume is &lt;strong&gt;git-like, not git-based&lt;/strong&gt;. It uses blobs, trees, commits, refs, and HEAD, but the storage, object format, and HTTP protocol are built from scratch. The whole thing compiles to a single &lt;strong&gt;100 KB&lt;/strong&gt; native binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benchmark that surprised me
&lt;/h2&gt;

&lt;p&gt;I compared the one workflow every developer repeats all day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lume add . &amp;amp;&amp;amp; lume commit -m "x"&lt;/code&gt; → &lt;strong&gt;~15 ms&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git add . &amp;amp;&amp;amp; git commit -m "x"&lt;/code&gt; → &lt;strong&gt;~17 ms&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On 110 small files, lume is faster. The lume binary is ~36× smaller than git (100 KB vs 3.7 MB), and the &lt;code&gt;.lume&lt;/code&gt; metadata is within 2% of &lt;code&gt;.git&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the speed comes from
&lt;/h2&gt;

&lt;p&gt;The biggest win was replacing the SQLite staging index with a line-delimited file. &lt;code&gt;lume add&lt;/code&gt; now builds a small tab-separated string and writes it once. Object subdirectories are created lazily, and blobs use a hand-rolled JSON fast path instead of generic serialization.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP push / pull / clone out of the box
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;lume serve&lt;/code&gt; starts a tiny HTTP object server. &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, and &lt;code&gt;clone&lt;/code&gt; speak plain JSON-over-HTTP. No SSH keys, no pack negotiation, no stateful transport.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Merge, rebase, and diff are still missing, and the tooling is Linux-oriented right now. But the core agent loop — init, add, commit, push, pull, clone — is fast enough to run behind automation without the automation ever knowing it is talking to a VCS.&lt;/p&gt;

&lt;p&gt;I wrote a longer post with the architecture and numbers on the &lt;a href="https://blog.intrane.fr/lume-git-like-vcs-beats-git-add-commit" rel="noopener noreferrer"&gt;Intrane blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Source, benchmarks, and build instructions are on GitHub: &lt;a href="https://github.com/javimosch/lume" rel="noopener noreferrer"&gt;github.com/javimosch/lume&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>vcs</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>rcmd now speaks MCP — your AI agent can manage your servers without SSH</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Sat, 18 Jul 2026 19:28:44 +0000</pubDate>
      <link>https://dev.to/javimosch/rcmd-now-speaks-mcp-your-ai-agent-can-manage-your-servers-without-ssh-3eck</link>
      <guid>https://dev.to/javimosch/rcmd-now-speaks-mcp-your-ai-agent-can-manage-your-servers-without-ssh-3eck</guid>
      <description>&lt;p&gt;I've been building rcmd, a relay-based remote command tool. No SSH keys, no open ports — your servers connect out to a relay, and you send commands through it.&lt;/p&gt;

&lt;p&gt;Today I shipped the thing I've wanted since day one: an MCP server.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is MCP?
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol is the standard way AI agents (Claude Code, Cursor, Windsurf, Devin) call external tools. Instead of shelling out to &lt;code&gt;ssh user@host "df -h"&lt;/code&gt; and parsing text, the agent calls a structured tool and gets JSON back.&lt;/p&gt;

&lt;h2&gt;
  
  
  What rcmd's MCP server exposes
&lt;/h2&gt;

&lt;p&gt;Four tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rcmd_list_targets&lt;/code&gt; — list your configured servers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rcmd_exec&lt;/code&gt; — run a command on a remote server, get stdout/stderr/exit code/duration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rcmd_cp&lt;/code&gt; — copy a file to a remote server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rcmd_health&lt;/code&gt; — check if a server is reachable + latency&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to set it up
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install rcmd and configure a target:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd add-target &lt;span class="nt"&gt;--name&lt;/span&gt; prod &lt;span class="nt"&gt;--token&lt;/span&gt; &amp;lt;token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add rcmd as an MCP server. For Claude Code (&lt;code&gt;~/.claude/mcp.json&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rcmd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rcmd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="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;Same config for Cursor (&lt;code&gt;.cursor/mcp.json&lt;/code&gt;) and Windsurf (&lt;code&gt;~/.codeium/windsurf/mcp_config.json&lt;/code&gt;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;That's it. Your AI agent can now run commands on your servers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;You ask Claude: "Check disk space on prod"&lt;/p&gt;

&lt;p&gt;Claude calls &lt;code&gt;rcmd_exec&lt;/code&gt; with &lt;code&gt;{"target": "prod", "command": "df -h"}&lt;/code&gt; and gets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"df -h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stdout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Filesystem      Size  Used Avail Use% Mounted on&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;/dev/vda1       40G   28G   11G  73% /"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exit_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"142ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No SSH parsing. No "which server was that again?" No key management.&lt;/p&gt;

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

&lt;p&gt;I built rcmd because SSH is friction for AI agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keys need to be on the right machine&lt;/li&gt;
&lt;li&gt;Firewalls block inbound ports&lt;/li&gt;
&lt;li&gt;NAT makes connecting impossible without a VPN&lt;/li&gt;
&lt;li&gt;Parsing terminal output wastes tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;rcmd's daemon connects &lt;strong&gt;out&lt;/strong&gt; to a relay. No inbound ports. No keys on the agent's machine. The MCP server reads your local rcmd config and handles the rest.&lt;/p&gt;

&lt;p&gt;The agent never sees your tokens. It only sees target names. All traffic goes through the relay with token-based auth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-host or use the hosted relay
&lt;/h2&gt;

&lt;p&gt;The relay is open source (MIT). You can self-host it in 5 minutes — one binary, one port, done. Or use the hosted one at rcmd.intrane.fr for €5/mo.&lt;/p&gt;

&lt;p&gt;Full self-hosting guide: &lt;a href="https://github.com/javimosch/remotecmd-cli/blob/main/docs/self-hosting.md" rel="noopener noreferrer"&gt;https://github.com/javimosch/remotecmd-cli/blob/main/docs/self-hosting.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MCP server docs: &lt;a href="https://github.com/javimosch/remotecmd-cli/blob/main/docs/mcp-server.md" rel="noopener noreferrer"&gt;https://github.com/javimosch/remotecmd-cli/blob/main/docs/mcp-server.md&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;More MCP tools (cron management, tunnel setup, team operations)&lt;/li&gt;
&lt;li&gt;Resources (expose server state as MCP resources, not just tools)&lt;/li&gt;
&lt;li&gt;Streaming output for long-running commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The binary is ~6MB, single file, no dependencies. Linux + macOS, amd64 + arm64.&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;# Download from GitHub releases&lt;/span&gt;
&lt;span class="c"&gt;# Or: curl -sSL https://github.com/javimosch/remotecmd-cli/releases/latest | ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/javimosch/remotecmd-cli" rel="noopener noreferrer"&gt;https://github.com/javimosch/remotecmd-cli&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;rcmd is agent-first infrastructure. Every command returns structured JSON. Every feature is designed to be called by an AI, not just a human. The MCP server is the natural endpoint of that design.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>automation</category>
      <category>tools</category>
    </item>
    <item>
      <title>Web Analytics With No Dashboard (But There Is a 3D Globe)</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Sat, 18 Jul 2026 18:27:07 +0000</pubDate>
      <link>https://dev.to/javimosch/web-analytics-with-no-dashboard-but-there-is-a-3d-globe-jn0</link>
      <guid>https://dev.to/javimosch/web-analytics-with-no-dashboard-but-there-is-a-3d-globe-jn0</guid>
      <description>&lt;p&gt;I built &lt;a href="https://github.com/javimosch/vigie" rel="noopener noreferrer"&gt;vigie&lt;/a&gt; — cookieless web analytics where the primary consumer is an AI agent, not a human staring at charts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The premise
&lt;/h2&gt;

&lt;p&gt;Every privacy-first analytics tool (Plausible, Fathom, Rybbit) assumes a human logs into a dashboard. My team is agents: they write the code, send the email, file the issues. They need analytics they can &lt;strong&gt;query and act on&lt;/strong&gt; — JSON on stdout, semantic exit codes, a machine-readable API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vigie stats overview &lt;span class="nt"&gt;--site&lt;/span&gt; example.com &lt;span class="nt"&gt;--since&lt;/span&gt; 7d
&lt;span class="c"&gt;# {"ok":true,"data":{"pageviews":1234,"visitors":410,"bounce_rate_pct":38,...}}&lt;/span&gt;
vigie stats cities &lt;span class="nt"&gt;--site&lt;/span&gt; example.com     &lt;span class="c"&gt;# geo down to city + coordinates&lt;/span&gt;
vigie stats journeys &lt;span class="nt"&gt;--site&lt;/span&gt; example.com   &lt;span class="c"&gt;# the sankey, as JSON&lt;/span&gt;
vigie stats vitals &lt;span class="nt"&gt;--site&lt;/span&gt; example.com     &lt;span class="c"&gt;# LCP/FCP/CLS/INP/TTFB p50/75/90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When a human needs to see it
&lt;/h2&gt;

&lt;p&gt;The dashboard is an &lt;strong&gt;artifact&lt;/strong&gt;: &lt;code&gt;vigie snapshot --publish&lt;/code&gt; renders every metric (22 sections — journeys, channels, heatmap, vitals, errors, geo to city…) into one self-contained HTML page and publishes it to an artifact host. Regenerated on a timer, never stale, no frontend server to run. &lt;a href="https://hart.intrane.fr/a/vigie/report-demo" rel="noopener noreferrer"&gt;Fully-populated demo report here&lt;/a&gt; (synthetic data, labeled).&lt;/p&gt;

&lt;p&gt;And one indulgence: your traffic as a &lt;a href="https://hart.intrane.fr/a/vigie/intrane-globe" rel="noopener noreferrer"&gt;living 3D globe&lt;/a&gt; — hand-rolled canvas math, city-level dots, repaints itself from the live feed. Zero JS frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interesting constraints
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cookieless by construction&lt;/strong&gt;: visitor = &lt;code&gt;sha256(secret + day + site + ip + ua)&lt;/code&gt;, daily salt rotation, raw IP never stored. Nothing to consent to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents are users too&lt;/strong&gt;: &lt;code&gt;vigie track --name deploy --actor ci&lt;/code&gt; records server-side events — your cron job is a first-class analytics stream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One ~300 KB binary&lt;/strong&gt; (HTTP ingest + SQLite + stats engine + globe renderer + CLI), written in &lt;a href="https://github.com/javimosch/machin" rel="noopener noreferrer"&gt;MFL&lt;/a&gt;, no Node/ClickHouse/Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geo without a SaaS&lt;/strong&gt;: a MaxMind-DB (.mmdb) reader written from scratch in MFL, reading DB-IP City Lite (CC BY). ~300 lines for the binary tree walk + data-section decoder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An agent built the whole thing in a day, and found three compiler bugs in the process — including string literals silently corrupted by C trigraph processing (&lt;code&gt;??&lt;/code&gt; became &lt;code&gt;^&lt;/code&gt; in the globe JavaScript, surfacing as a browser SyntaxError three layers away).&lt;/p&gt;

&lt;p&gt;Full story: &lt;a href="https://blog.intrane.fr/analytics-with-no-dashboard" rel="noopener noreferrer"&gt;https://blog.intrane.fr/analytics-with-no-dashboard&lt;/a&gt;&lt;br&gt;
Repo (MIT): &lt;a href="https://github.com/javimosch/vigie" rel="noopener noreferrer"&gt;https://github.com/javimosch/vigie&lt;/a&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>I built a database my AI agent can pay for (and it beat SQLite)</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Sat, 18 Jul 2026 13:03:35 +0000</pubDate>
      <link>https://dev.to/javimosch/i-built-a-database-my-ai-agent-can-pay-for-and-it-beat-sqlite-58m7</link>
      <guid>https://dev.to/javimosch/i-built-a-database-my-ai-agent-can-pay-for-and-it-beat-sqlite-58m7</guid>
      <description>&lt;p&gt;Every database assumes a human shows up eventually — to create the account, paste a card, click through a console. AI agents can't do any of that. So I built &lt;a href="https://github.com/javimosch/grange" rel="noopener noreferrer"&gt;grange&lt;/a&gt;: a document database where &lt;strong&gt;a payment wallet is the signup&lt;/strong&gt;.&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;-X&lt;/span&gt; POST https://grange.intrane.fr/tenants &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Peage-Wallet: pw_...'&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_..."}   your isolated, metered namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pricing is pay-as-you-go: &lt;strong&gt;€0.15/GB/month above 50 MB free, queries free&lt;/strong&gt;, billed continuously through &lt;a href="https://peage.intrane.fr" rel="noopener noreferrer"&gt;péage&lt;/a&gt; — no subscription, no card on file, no human in the loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The engine
&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;, my language for AI agents, and two properties fell out of the language rather than being engineered in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crash-safe by construction.&lt;/strong&gt; The language has no file append or rename, so every commit is one immutable, sha256-trailered WAL chunk. &lt;code&gt;kill -9&lt;/code&gt; at any moment leaves exactly the committed prefix — the repo ships the harness that proves it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Race-free by proof.&lt;/strong&gt; The server is a single actor with zero goroutines, and machin's inferred data-race analysis verifies the whole engine on every build. No Send/Sync, no annotations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The benchmark (100k docs, both engines indexed, same box)
&lt;/h2&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;indexed count × 1000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&amp;lt;1 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.5 s&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; (write-time registers)&lt;/td&gt;
&lt;td&gt;49 s&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;&lt;/td&gt;
&lt;td&gt;257 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The aggregate rows aren't typos: declare &lt;code&gt;--sums&lt;/code&gt; on an index and grange maintains per-group count/sum/avg &lt;strong&gt;at write time&lt;/strong&gt; — a group-by answer costs a map lookup. The one row SQLite wins (unindexed full scan, 8ms vs 61ms) is in the README too, because a benchmark you can't lose is marketing, not measurement. &lt;code&gt;make bench&lt;/code&gt; reproduces everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dogfooding found three compiler bugs in one day
&lt;/h2&gt;

&lt;p&gt;This is why I build real things in my own language. The first bench ran 70× slow — stale compiler binary, maps were O(n). The billing math went negative — integer literals compiled to bare C constants and &lt;code&gt;30 * 86400000&lt;/code&gt; overflowed in 32-bit before widening. A WAL tombstone turned to garbage — &lt;code&gt;keys(map)&lt;/code&gt; aliased internal storage that &lt;code&gt;delete()&lt;/code&gt; freed: a use-after-free handed to me by a failing test. All three fixes went back into the language.&lt;/p&gt;

&lt;h2&gt;
  
  
  For humans: client SDKs
&lt;/h2&gt;

&lt;p&gt;Agents speak curl; humans expect drivers. So: &lt;strong&gt;Node.js&lt;/strong&gt; (&lt;code&gt;npm i grange-db&lt;/code&gt;), &lt;strong&gt;Go&lt;/strong&gt; (&lt;code&gt;go get github.com/javimosch/grange/sdk/go&lt;/code&gt;), and machin. Same surface: &lt;code&gt;db("crm").coll("leads")&lt;/code&gt;, &lt;code&gt;put/get/find/count/agg&lt;/code&gt;, bulk writes at 263k docs/s over HTTP.&lt;/p&gt;

&lt;p&gt;The full story is on my blog: &lt;a href="https://blog.intrane.fr/a-database-your-agent-can-pay-for" rel="noopener noreferrer"&gt;grange: A Database Your Agent Can Pay For&lt;/a&gt;. The contract, written for agents: &lt;a href="https://grange.intrane.fr/llms.txt" rel="noopener noreferrer"&gt;grange.intrane.fr/llms.txt&lt;/a&gt;. MIT, one binary, no lock-in.&lt;/p&gt;

</description>
      <category>database</category>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>rcmd: I replaced SSH with a relay — now my AI agents manage my servers</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Sat, 18 Jul 2026 03:51:56 +0000</pubDate>
      <link>https://dev.to/javimosch/rcmd-i-replaced-ssh-with-a-relay-now-my-ai-agents-manage-my-servers-3lh4</link>
      <guid>https://dev.to/javimosch/rcmd-i-replaced-ssh-with-a-relay-now-my-ai-agents-manage-my-servers-3lh4</guid>
      <description>&lt;p&gt;I run a small infrastructure. A few VPS, some Proxmox boxes, a Raspberry Pi. Every time I needed to run a command on a remote machine, it was the same ritual: SSH key, port, firewall, VPN if the box is behind NAT. And my AI agents? They couldn't do any of it without me handing them SSH keys or setting up tunnels.&lt;/p&gt;

&lt;p&gt;So I built rcmd — a zero-config remote command execution tool. No SSH keys, no open ports, no VPN. A WebSocket relay brokers connections between your machine and remote targets. The daemon on the target connects outbound. You run the CLI. The relay routes the command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You ──wss──► relay ──wss──► target daemon (runs your command, returns output)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What shipped this week
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scheduled commands (cron)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd cron add &lt;span class="nt"&gt;--target&lt;/span&gt; prod &lt;span class="nt"&gt;--schedule&lt;/span&gt; &lt;span class="s2"&gt;"0 3 * * *"&lt;/span&gt; &lt;span class="nt"&gt;--cmd&lt;/span&gt; &lt;span class="s2"&gt;"docker restart app"&lt;/span&gt;
rcmd cron list
rcmd cron logs &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;job-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relay runs a scheduler goroutine. When a job fires, it forwards the command to the target daemon. If the target is offline, the run is logged as "skipped" — no retry queue, the next tick tries again. History persists across relay restarts.&lt;/p&gt;

&lt;p&gt;This replaces the crontab + SSH + monitoring script combo with one command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Port forwarding (tunnel)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd tunnel &lt;span class="nt"&gt;--target&lt;/span&gt; db &lt;span class="nt"&gt;--local&lt;/span&gt; 5432 &lt;span class="nt"&gt;--remote&lt;/span&gt; 127.0.0.1:5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forwards a local port to a remote address through the target daemon. Replaces &lt;code&gt;ssh -L&lt;/code&gt;. Useful for reaching a database or service that's only listening on localhost on the remote machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Team access
&lt;/h3&gt;

&lt;p&gt;This is the one I'm most excited about. The problem: one token = full access to all targets. If you want a teammate or an AI agent to run commands, you either share your master token (security nightmare) or set up a separate account (no shared targets).&lt;/p&gt;

&lt;p&gt;Now you generate scoped sub-tokens:&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;# Give an operator access to prod + staging&lt;/span&gt;
rcmd team token &lt;span class="nt"&gt;--role&lt;/span&gt; operator &lt;span class="nt"&gt;--targets&lt;/span&gt; prod,staging &lt;span class="nt"&gt;--label&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt; &lt;span class="nt"&gt;--expires&lt;/span&gt; 24h

&lt;span class="c"&gt;# Bob runs:&lt;/span&gt;
rcmd login tok_operator_abc123...
&lt;span class="c"&gt;# His access is scoped — he can only touch prod + staging, all audited&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three roles: &lt;strong&gt;admin&lt;/strong&gt; (everything except billing), &lt;strong&gt;operator&lt;/strong&gt; (exec, copy, tunnel, cron on assigned targets), &lt;strong&gt;viewer&lt;/strong&gt; (read-only — list targets, check health, view cron logs).&lt;/p&gt;

&lt;p&gt;Every command execution is recorded in the audit log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd team audit &lt;span class="nt"&gt;--target&lt;/span&gt; prod &lt;span class="nt"&gt;--since&lt;/span&gt; 24h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Email invites
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd team invite &lt;span class="nt"&gt;--email&lt;/span&gt; bob@company.com &lt;span class="nt"&gt;--role&lt;/span&gt; operator &lt;span class="nt"&gt;--targets&lt;/span&gt; prod,staging &lt;span class="nt"&gt;--label&lt;/span&gt; &lt;span class="s2"&gt;"Bob"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sends an HTML email with a 7-day invite code. Bob clicks the link, sees a page with the accept command and a copy-to-clipboard button, runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd team accept inv_5b97e6eeb72d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gets a scoped sub-token. Done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent-first discovery
&lt;/h2&gt;

&lt;p&gt;This is the part that matters if you're building tools for AI agents. rcmd is designed to be operated by agents, not just humans. So I added three discovery surfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/llms.txt&lt;/code&gt;&lt;/strong&gt; — a short breadcrumb at &lt;code&gt;rcmd.intrane.fr/llms.txt&lt;/code&gt;. An AI assistant that only knows the domain fetches this and gets oriented.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/guide&lt;/code&gt;&lt;/strong&gt; — the full operator reference. Every command, every flag, cron scheduling, tunnels, team access, JSON output format, exit codes, gotchas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rcmd guide&lt;/code&gt;&lt;/strong&gt; — CLI subcommand that prints the same guide locally. An agent on a machine with rcmd installed runs this to learn the full feature surface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern: an agent finds itself on a machine with &lt;code&gt;rcmd&lt;/code&gt; → runs &lt;code&gt;rcmd guide&lt;/code&gt; → learns everything. An agent that only knows the domain → fetches &lt;code&gt;/llms.txt&lt;/code&gt; → gets pointed to &lt;code&gt;/guide&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why no SSH?
&lt;/h2&gt;

&lt;p&gt;SSH is designed for humans typing into terminals. It's not designed for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agents&lt;/strong&gt; that need to run commands programmatically and parse output&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NAT traversal&lt;/strong&gt; — if the target is behind NAT, you need a VPN or a jump host&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoped access&lt;/strong&gt; — SSH keys grant full shell access; there's no easy way to say "this agent can only restart this one service on this one server"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit trails&lt;/strong&gt; — SSH logs connections, not commands (unless you set up auditd or similar)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;rcmd solves these by moving the routing to a relay. The daemon connects outbound (no firewall changes). Tokens are scoped (admin/operator/viewer, target-restricted). Every command is audited. And the CLI is designed for agents — JSON output, semantic exit codes, a guide command that teaches the agent everything it can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go binary, single file, ~7MB stripped&lt;/li&gt;
&lt;li&gt;WebSocket relay (runs on a VPS, behind Traefik + Let's Encrypt)&lt;/li&gt;
&lt;li&gt;JSON file storage (no database — teams, cron jobs, audit logs, customers)&lt;/li&gt;
&lt;li&gt;Resend for transactional email (team invites)&lt;/li&gt;
&lt;li&gt;Stripe for billing (Pro tier)&lt;/li&gt;
&lt;li&gt;21 unit tests, all passing&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;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://rcmd.intrane.fr/install.sh | sh
rcmd signup &lt;span class="nt"&gt;--email&lt;/span&gt; you@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The free tier gives you the relay. Pro adds scheduled commands, tunnels, and team access.&lt;/p&gt;

&lt;p&gt;Full reference: &lt;code&gt;rcmd guide&lt;/code&gt; or &lt;a href="https://rcmd.intrane.fr/guide" rel="noopener noreferrer"&gt;https://rcmd.intrane.fr/guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/javimosch/remotecmd-cloud" rel="noopener noreferrer"&gt;https://github.com/javimosch/remotecmd-cloud&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by &lt;a href="https://intrane.fr" rel="noopener noreferrer"&gt;Javier Leandro Arancibia&lt;/a&gt; — making infrastructure agent-first, one tool at a time.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>devops</category>
      <category>saas</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I replaced ssh -L with one CLI command. No SSH keys, no VPN, no open ports.</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Fri, 17 Jul 2026 11:56:31 +0000</pubDate>
      <link>https://dev.to/javimosch/i-replaced-ssh-l-with-one-cli-command-no-ssh-keys-no-vpn-no-open-ports-91j</link>
      <guid>https://dev.to/javimosch/i-replaced-ssh-l-with-one-cli-command-no-ssh-keys-no-vpn-no-open-ports-91j</guid>
      <description>&lt;p&gt;If you manage servers, you've done this a thousand times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-L&lt;/span&gt; 5432:localhost:5432 user@prod-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. But it requires SSH keys, an open port 22, a VPN if you're behind NAT, and a running SSH daemon on the target. Every one of those is a maintenance burden and an attack surface.&lt;/p&gt;

&lt;p&gt;I just shipped &lt;code&gt;rcmd tunnel&lt;/code&gt; — port forwarding through a WebSocket relay. No SSH, no VPN, no open ports.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your laptop ──wss──► Relay ──wss──► Target daemon ──► localhost:5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The target runs a tiny daemon (~6 MB Go binary) that connects outbound to a relay. Your client connects to the same relay. The relay routes TCP data between them. That's it.&lt;/p&gt;

&lt;p&gt;Both sides connect outbound. No inbound ports. Works behind NAT, firewalls, corporate proxies.&lt;/p&gt;

&lt;h2&gt;
  
  
  The command
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rcmd tunnel &lt;span class="nt"&gt;--target&lt;/span&gt; prod &lt;span class="nt"&gt;--local&lt;/span&gt; 5432 &lt;span class="nt"&gt;--remote&lt;/span&gt; localhost:5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;localhost:5432&lt;/code&gt; on your machine tunnels to &lt;code&gt;prod:5432&lt;/code&gt;. You can connect with &lt;code&gt;psql&lt;/code&gt;, &lt;code&gt;redis-cli&lt;/code&gt;, a browser dashboard — anything that speaks TCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can tunnel
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; — &lt;code&gt;--local 5432 --remote localhost:5432&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis&lt;/strong&gt; — &lt;code&gt;--local 6379 --remote localhost:6379&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug dashboards&lt;/strong&gt; — &lt;code&gt;--local 8080 --remote localhost:8080&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jupyter notebooks&lt;/strong&gt; running on a remote GPU box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal admin panels&lt;/strong&gt; behind a firewall&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any TCP service&lt;/strong&gt; — if it speaks TCP, rcmd tunnels it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  But wait, I already have SSH
&lt;/h2&gt;

&lt;p&gt;So did I. Here's why I built this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SSH requires port 22 open.&lt;/strong&gt; Every server with an open SSH port is a brute-force target. rcmd's daemon connects outbound — zero inbound ports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH key management is a tax.&lt;/strong&gt; Rotate keys, distribute them, revoke them, deal with &lt;code&gt;known_hosts&lt;/code&gt; pollution. rcmd uses per-target tokens, auto-generated, no files to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH doesn't work behind NAT.&lt;/strong&gt; If your server is behind a corporate firewall or NAT, you need a VPN just to reach it. rcmd works from anywhere — both sides connect outbound to the relay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH isn't built for automation.&lt;/strong&gt; Parsing SSH output in scripts is fragile. rcmd returns structured JSON for every command — stdout, stderr, exit code, duration. Built for AI agents and CI/CD pipelines.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  It's also a remote execution tool
&lt;/h2&gt;

&lt;p&gt;Tunneling is just one feature. rcmd also does:&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;# Execute a command on a remote machine&lt;/span&gt;
rcmd &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; prod &lt;span class="nt"&gt;--cmd&lt;/span&gt; &lt;span class="s1"&gt;'docker ps'&lt;/span&gt; &lt;span class="nt"&gt;--timeout&lt;/span&gt; 10

&lt;span class="c"&gt;# Run the same command across 10 servers at once&lt;/span&gt;
rcmd &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--targets&lt;/span&gt; web1,web2,web3,db1 &lt;span class="nt"&gt;--cmd&lt;/span&gt; &lt;span class="s1"&gt;'uptime'&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; table

&lt;span class="c"&gt;# Check fleet health&lt;/span&gt;
rcmd list-targets

&lt;span class="c"&gt;# Copy files&lt;/span&gt;
rcmd &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; prod &lt;span class="nt"&gt;--src&lt;/span&gt; ./app.tar.gz &lt;span class="nt"&gt;--dst&lt;/span&gt; /opt/app/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every command returns JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stdout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CONTAINER ID   IMAGE   ..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exit_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duration_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;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No parsing. No guessing. No wasted tokens when an AI agent uses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosted or hosted
&lt;/h2&gt;

&lt;p&gt;Two ways to run it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free (OSS)&lt;/strong&gt;: Self-host the relay on any VPS. Unlimited targets, all features. MIT licensed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro (€5/mo)&lt;/strong&gt;: We host the relay at rcmd.intrane.fr. Automatic TLS, no infrastructure to manage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same binary, same features. The hosted version just means you don't run the relay yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&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;-sSL&lt;/span&gt; https://rcmd.intrane.fr/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then either self-host a relay or &lt;code&gt;rcmd signup --email you@company.com&lt;/code&gt; for the hosted version.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Tunnel is the first of three SSH-killer features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Port forwarding&lt;/strong&gt; — shipped today&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled commands&lt;/strong&gt; — &lt;code&gt;rcmd cron add --target prod --cmd 'docker restart app' --schedule '0 3 * * *'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive shell&lt;/strong&gt; — full PTY sessions, &lt;code&gt;rcmd exec --target prod --pty&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is simple: make SSH optional for the 80% of server access that doesn't require a full interactive session.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;: &lt;a href="https://rcmd.intrane.fr" rel="noopener noreferrer"&gt;rcmd.intrane.fr&lt;/a&gt; · &lt;a href="https://github.com/javimosch/remotecmd-cli" rel="noopener noreferrer"&gt;GitHub (OSS)&lt;/a&gt; · &lt;a href="https://rcmd.intrane.fr/install.sh" rel="noopener noreferrer"&gt;Install&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Made in France. MIT licensed. Built for AI agents first, humans second.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>devops</category>
      <category>cli</category>
      <category>remotework</category>
    </item>
    <item>
      <title>I ran a 7B Mixture-of-Experts LLM in a language I built — token-identical to fp32</title>
      <dc:creator>Javier Leandro Arancibia</dc:creator>
      <pubDate>Thu, 16 Jul 2026 19:01:45 +0000</pubDate>
      <link>https://dev.to/javimosch/i-ran-a-7b-mixture-of-experts-llm-in-a-language-i-built-token-identical-to-fp32-26m9</link>
      <guid>https://dev.to/javimosch/i-ran-a-7b-mixture-of-experts-llm-in-a-language-i-built-token-identical-to-fp32-26m9</guid>
      <description>&lt;p&gt;I've been building &lt;strong&gt;machin&lt;/strong&gt; (MFL), a machine-first language, and using it to write an LLM inference engine with &lt;strong&gt;zero dependencies&lt;/strong&gt; — no PyTorch, no llama.cpp, no BLAS, no Python at runtime. Just a static binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wall
&lt;/h2&gt;

&lt;p&gt;A dense 1B model got me ~20 tok/s on a laptop CPU. That's the ceiling, and it's &lt;em&gt;fundamental&lt;/em&gt;: decode speed is set by &lt;strong&gt;bytes moved per token&lt;/strong&gt;, and on weak hardware you're pinned to the memory bus. I built and measured every trick — speculative decoding, int4, contextual sparsity, early-exit, continuous batching. Every one topped out at ~1.35×, because the box is balanced: save bandwidth and you go compute-bound, and vice-versa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The disruption isn't in the engine. It's in the model.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mixture-of-Experts
&lt;/h2&gt;

&lt;p&gt;A dense model prices every token at its &lt;em&gt;total&lt;/em&gt; params. An MoE decouples quality from speed: only a few experts fire per token. &lt;a href="https://huggingface.co/allenai/OLMoE-1B-7B-0924" rel="noopener noreferrer"&gt;OLMoE-1B-7B&lt;/a&gt; is &lt;strong&gt;6.9B total but 1.3B active&lt;/strong&gt; (top-8 of 64 experts/layer). And since only a handful fire, you &lt;code&gt;mmap&lt;/code&gt; the checkpoint and let the OS page cache &lt;strong&gt;stream cold experts from disk&lt;/strong&gt; — total size bounded by disk, not RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  It works — and it's exact
&lt;/h2&gt;

&lt;p&gt;I wrote an fp32 numpy reference reading the original weights, and checked my pure-MFL int8 engine against it token for token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;numpy fp32 : The capital of France is Paris. The capital of the United States is Washington
pure MFL   : The capital of France is Paris. The capital of the United States is Washington
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;12/12 tokens identical.&lt;/strong&gt; Quantization didn't flip one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;experts&lt;/th&gt;
&lt;th&gt;lm_head&lt;/th&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;tok/s&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;int8&lt;/td&gt;
&lt;td&gt;int8&lt;/td&gt;
&lt;td&gt;7.65 GB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14.5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int4&lt;/td&gt;
&lt;td&gt;int8&lt;/td&gt;
&lt;td&gt;4.43 GB&lt;/td&gt;
&lt;td&gt;11.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;int8 lm_head buys speed (memory-bound); int4 experts buy footprint. Then I wrapped it in an OpenAI-compatible server — tokenizer and all in pure MFL — and pointed the official &lt;code&gt;openai&lt;/code&gt; client at it. Works.&lt;/p&gt;

&lt;p&gt;7B-class quality, ~1B speed, on hardware you own, no numeric libraries anywhere.&lt;/p&gt;

&lt;p&gt;Full write-up: &lt;a href="https://blog.intrane.fr/a-7b-moe-llm-at-1b-speed-in-pure-machin" rel="noopener noreferrer"&gt;https://blog.intrane.fr/a-7b-moe-llm-at-1b-speed-in-pure-machin&lt;/a&gt;&lt;br&gt;
Code (engine, converters, tokenizer, every dead end): &lt;a href="https://github.com/javimosch/machin-colibri" rel="noopener noreferrer"&gt;https://github.com/javimosch/machin-colibri&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
