<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xml.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>iammatthias — #side-projects</title><description>Entries tagged side-projects.</description><link>https://iammatthias.com/</link><language>en-us</language><item><title>Intern</title><link>https://iammatthias.com/posts/1781835006151-intern/</link><guid isPermaLink="true">https://iammatthias.com/posts/1781835006151-intern/</guid><description>The Autonomous Intern ships as a Raspberry Pi 5 in a desk-toy case running a stack I didn&apos;t pick. I flashed it to Debian Trixie, swapped the whole thing for the Hermes agent with its own built-in memory, and folded it all into one setup script.</description><pubDate>Fri, 19 Jun 2026 02:10:06 GMT</pubDate><content:encoded>&lt;p&gt;Ah, the Autonomous Intern. A glorious little housing meant to sit on your desk with its LEDs flashing, letting you know it&amp;#39;s hard at work on whatever you threw at the agent it&amp;#39;s running.&lt;/p&gt;
&lt;p&gt;Out of the box, the Intern is a Raspberry Pi 5 with 4 GB of RAM and a 64 GB SD card. It ships with a factory install (the docs imply Debian Bookworm), and when you plug it in, it boots into access point mode. You connect to its wifi network (&lt;code&gt;Intern-XXXX&lt;/code&gt;) and set it up from there.&lt;/p&gt;
&lt;p&gt;You can also pop the case open by removing four screws, minding the wires for the LED array. With some tweezers you can pop the SD card and flash it with whatever you want. It&amp;#39;s a Pi! Have some fun with it.&lt;/p&gt;
&lt;p&gt;Well, I had some fun with it. I reworked the &lt;a href=&quot;https://cdn.autonomous.ai/intern/setup.sh&quot;&gt;setup script&lt;/a&gt; Autonomous provides with some defaults that I preferred:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debian Trixie instead of Bookworm&lt;/li&gt;
&lt;li&gt;Caddy instead of nginx&lt;/li&gt;
&lt;li&gt;Hermes instead of OpenClaw (the stock default)&lt;/li&gt;
&lt;li&gt;Supermemory dropped for the default Hermes memory (&lt;a href=&quot;https://x.com/Teknium/status/2067030389538083183&quot;&gt;recommended by Teknium, who leads Hermes&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The agent&lt;/h2&gt;
&lt;p&gt;The brain is now &lt;a href=&quot;https://github.com/NousResearch/hermes-agent&quot;&gt;Hermes&lt;/a&gt;, the agent from Nous Research. It runs as a gateway service on the Pi and talks over whatever channels you wire up. Bring your own model (I point it at OpenRouter) and pick it in a little web dashboard. Caddy sits out front, serving the setup page and proxying the backend. Nothing fancy, just the parts I trust doing the jobs I want.&lt;/p&gt;
&lt;h2&gt;Memory&lt;/h2&gt;
&lt;p&gt;This is the part I went back and forth on. I started by self-hosting &lt;a href=&quot;https://github.com/plastic-labs/honcho&quot;&gt;Honcho&lt;/a&gt; as a memory backend: Postgres, pgvector, Redis, a deriver worker, the whole Docker stack. It worked, and it was also a fragile, RAM-hungry pile of moving parts for what it actually bought me on a 4 GB Pi.&lt;/p&gt;
&lt;p&gt;So I ripped it out. The default Hermes memory is just a small &lt;code&gt;MEMORY.md&lt;/code&gt; the agent keeps current, plus skills it writes for itself. No vector database, no embeddings bill, and a lot less to run.&lt;/p&gt;
&lt;h2&gt;Reaching it&lt;/h2&gt;
&lt;p&gt;The Intern lives on my desk, but I don&amp;#39;t want to be at my desk to use it. &lt;a href=&quot;https://tailscale.com&quot;&gt;Tailscale&lt;/a&gt; handles that. The dashboard is published to my tailnet only, SSH goes over the tailnet, and a firewall locks the rest down so nothing interesting is exposed to the local network. From my phone or my laptop, anywhere, it&amp;#39;s just there.&lt;/p&gt;
&lt;h2&gt;The LEDs&lt;/h2&gt;
&lt;p&gt;Those flashing LEDs aren&amp;#39;t just for show. The backend drives the ring to track what the agent is doing. On my build, getting it to follow Hermes took a small bridge that feeds Hermes&amp;#39; activity to the backend&amp;#39;s LED API, so the ring breathes one color when it&amp;#39;s idle, another while it&amp;#39;s thinking, another while it&amp;#39;s running a tool.&lt;/p&gt;
&lt;h2&gt;The Rabbit R1&lt;/h2&gt;
&lt;p&gt;There&amp;#39;s one more goodie in the script: a shim that lets you pair a &lt;a href=&quot;https://www.rabbit.tech&quot;&gt;Rabbit R1&lt;/a&gt; to the Intern using the R1&amp;#39;s built-in OpenClaw pairing. Scan a QR and the R1 becomes a pocket remote for the agent. I wrote that part up on its own: &lt;a href=&quot;https://iammatthias.com/posts/1775069974473-replacing-rabbit-s-brain-connecting-a-rabbit-r1-to-hermes&quot;&gt;Replacing Rabbit&amp;#39;s Brain&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;One script&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s all one script. Flash a Raspberry Pi 5 with Debian Trixie, run it, and you get the whole stack: agent, web layer, memory, remote access, LEDs, and the optional R1 channel. It&amp;#39;s idempotent, so you can re-run it without thinking too hard, and it works out on its own whether to run wifi onboarding or use a connection you&amp;#39;ve already got.&lt;/p&gt;
&lt;p&gt;Repo&amp;#39;s here: &lt;a href=&quot;https://github.com/iammatthias/intern&quot;&gt;github.com/iammatthias/intern&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Posts</category><category>raspberry-pi</category><category>hardware</category><category>ai-agents</category><category>self-hosting</category><category>side-projects</category><category>hermes</category></item><item><title>Toy GPTs</title><link>https://iammatthias.com/posts/1780416704000-toy-gpts/</link><guid isPermaLink="true">https://iammatthias.com/posts/1780416704000-toy-gpts/</guid><description>Two tiny GPTs out of Karpathy&apos;s microGPT. One keeps its weights on Ethereum. The other holds a séance with dead presidents.</description><pubDate>Tue, 02 Jun 2026 16:11:44 GMT</pubDate><content:encoded>&lt;p&gt;Back in February, Karpathy released &lt;a href=&quot;https://karpathy.github.io/2026/02/12/microgpt/&quot;&gt;microGPT&lt;/a&gt;, 200 lines of dependency-free Python that trains a GPT: a scalar autograd engine, a small transformer, an optimizer, and a train loop, with nothing to import. It rattled around in my head for months. Two side projects came out of it.&lt;/p&gt;
&lt;p&gt;Meet Bard and Dead Presidents.&lt;/p&gt;
&lt;p&gt;Bard is a tiny GPT trained on &lt;a href=&quot;https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt&quot;&gt;Tiny Shakespeare&lt;/a&gt; whose weights live on Ethereum. Dead Presidents is trained on the inaugural and State of the Union addresses of presidents who have died.&lt;/p&gt;
&lt;h2&gt;What a GPT is, roughly&lt;/h2&gt;
&lt;p&gt;A GPT predicts the next token from the tokens before it. Show it enough text and it learns which token tends to follow which. To generate, you hand it a few tokens, ask what comes next, append the answer, and ask again.&lt;/p&gt;
&lt;p&gt;Both of these work one character at a time. The token is a single letter, space, or punctuation mark. Bard has a 66-character vocabulary, Dead Presidents has 34. They read a run of characters and guess the next one.&lt;/p&gt;
&lt;p&gt;These models continue text. Hand Dead Presidents &amp;quot;the state of the&amp;quot; and it runs with it, in the cadence it learned.&lt;/p&gt;
&lt;h2&gt;Bard&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://bard.farfield.systems/&quot;&gt;Bard&lt;/a&gt; trains offline in numpy, then puts its weights on chain. It is 811,520 parameters: 4 layers, 128 wide, a 64-character context. After training, an export step quantizes the weights to int8, gzips them to 684 KB, and hashes the result with SHA-256. That artifact goes on Ethereum.&lt;/p&gt;
&lt;p&gt;Normal contract storage would make 684 KB cost a fortune, so the weights ride on SSTORE2, which stores each chunk as the bytecode of a throwaway contract and reads it back far cheaper. The artifact splits into 29 chunks of 24,000 bytes, so the model lands on chain across 29 transactions inside a &lt;code&gt;WeightManifest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A CREATE2 salt grind lands the contract at a vanity address starting &lt;code&gt;0xBA2D&lt;/code&gt;. ba2d is bard in hex. The deploy commits that address first, empty, then sets the config (including the artifact hash) afterward, which keeps the address independent of the model. Once the uploader pushes and verifies every chunk, the owner calls &lt;code&gt;seal()&lt;/code&gt; and freezes the manifest for good.&lt;/p&gt;
&lt;p&gt;Inference happens in the browser. The frontend reads the 29 chunks straight off chain, reassembles them, gunzips, and checks the SHA-256 against the contract&amp;#39;s hash. It runs only on a match, which proves the weights in the browser are the ones the owner sealed. Then it generates Shakespeare-shaped text, a character at a time. This is a Sepolia testnet proof of concept, and at this size the output reads as Shakespeare without quite cohering.&lt;/p&gt;
&lt;h2&gt;Dead Presidents&lt;/h2&gt;
&lt;p&gt;Dead Presidents points the same architecture at American political speech. The corpus is every inaugural and State of the Union address from presidents who are no longer with us, George Washington in 1789 through George H.W. Bush. The corpus leaves out the five living presidents, which means the builder keeps &lt;code&gt;george_bush&lt;/code&gt; and drops &lt;code&gt;george_w_bush&lt;/code&gt;. That comes to 255 addresses, normalized into 30,725 lowercase sentences, around 3 million characters, a 34-token vocabulary. The State of the Union speeches are the bulk of it, and they pull the diction toward the administrative: secretary of the treasury, expenditures, appropriations.&lt;/p&gt;
&lt;p&gt;There are two engines for one model. The scalar engine is pure Python with no NumPy, running at about 8 seconds per training step. Every multiply and every gradient is a visible Python object, which makes it readable and unusably slow. The fast engine is the same math in NumPy at roughly 5,400 examples a second. They agree to machine precision, logits matching to about 1e-16, so you train on the fast one and sample through the slow legible one and get the same numbers.&lt;/p&gt;
&lt;p&gt;Slow training makes good weights expensive, so finding them became its own search. The search copies Karpathy&amp;#39;s autoresearch loop: one metric, a fixed step budget per run, keep the result if it improved. The metric is val_bpc, bits per character on a held-out split. Seven researcher agents each took one region (width, depth, learning-rate schedule, batch size, context length, attention heads, and a wildcard combo) across 59 experiments, then re-ran the top configs on three seeds to reject luck.&lt;/p&gt;
&lt;p&gt;Warmup mattered most. Without a 150-to-250-step warmup, every bigger model looked worse, an init-time instability that masqueraded as a capacity ceiling. Context length came next: block size 24 to 112 dropped the metric the whole way. Depth beat width at matched parameter counts.&lt;/p&gt;
&lt;p&gt;The numbers in one line: 5.09 to 2.04 to 1.667 to 1.530 to 1.475 bits per character. Untrained, then inaugural-only, then adding the State of the Union speeches, then scaling the model up, then training straight across sentence boundaries instead of one sentence at a time. The winner is 464,928 parameters (96 wide, 4 layers, 192 context), about 1.8 MB as float32.&lt;/p&gt;
&lt;p&gt;The samples come out unmistakably presidential and not quite grammatical:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;the constitution of the country and personal agreement has been made in the state of the union.

our efforts is the soviet union and the prosperity of the secretary of the united states.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One phrase reaches back to the 1800s, another to the Cold War, both from 34 characters and 465k parameters. It runs client-side too. A Web Worker holds the weights behind an OpenAI-shaped API, and the chat UI seeds from your message and continues in dead-president voice, a séance with live token counts.&lt;/p&gt;
&lt;h2&gt;Farfield&lt;/h2&gt;
&lt;p&gt;Both ship their weights to the browser and run them in a Web Worker, a character at a time. They land on &lt;a href=&quot;1779064713644-farfield.md&quot;&gt;Farfield&lt;/a&gt;, the catch-all domain for my side projects and self-hosted services. Bard is live there now; Dead Presidents goes up today.&lt;/p&gt;
</content:encoded><category>Posts</category><category>machine-learning</category><category>gpt</category><category>transformers</category><category>ethereum</category><category>onchain</category><category>browser</category><category>side-projects</category></item><item><title>Adventures in Machine Vision</title><link>https://iammatthias.com/posts/1780360240000-adventures-in-machine-vision/</link><guid isPermaLink="true">https://iammatthias.com/posts/1780360240000-adventures-in-machine-vision/</guid><description>A Nat Friedman anecdote about an AI watching him drink water sent me digging for a spare Raspberry Pi. Now a camera and a sensor HAT watch my desk, a self-inflicted panopticon that logs who walks by and what the room is doing.</description><pubDate>Tue, 02 Jun 2026 00:30:40 GMT</pubDate><content:encoded>&lt;p&gt;A Nat Friedman anecdote recently caught my eye:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://wsrv.nl/?url=https%3A%2F%2Fblobs.farfield.systems%2Fblobs%2Fbafkreihzqgr2igbs5ggops54ad7vb5bjy6zlwnsnltb6nvzcqfegqs5gs4&amp;amp;w=960&amp;amp;q=80&amp;amp;output=webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;&lt;p&gt;Most of it is fluff. Friedman, Daniel Gross, and the Collisons are positioned to consume AI at a level most of us only read about: all the toys, all the tokens, early access, and people on payroll to wire it together. A lot of what gets demoed from that vantage point is a postcard from a budget I don&amp;#39;t have. But the kernel of the idea is almost always cheap, you don&amp;#39;t need their resources to point some consumer hardware at yourself and see what falls out.&lt;/p&gt;
&lt;p&gt;Now I need to preface this by making it clear that blanketing your house with cameras and letting an AI watch you 24/7 sounds dystopian.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I want you to walk to the kitchen right now and drink a bottle of water, and I&amp;#39;m going to watch to make sure you do it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Maybe dystopian is the wrong word. This is self-inflicted panopticon horror.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s build our own.&lt;/p&gt;
&lt;h2&gt;The build&lt;/h2&gt;
&lt;p&gt;I had a spare Raspberry Pi Zero 2 W rattling around in a drawer, so I gave it a job. A 5MP Arducam (the OV5647, a native Pi sensor, so no driver wrangling) rides the camera ribbon, and a repurposed Waveshare Environment Sensor HAT sits on the GPIO header. The camera and the HAT use different connectors, so they coexist on one board on my desk.&lt;/p&gt;
&lt;p&gt;The pipeline is small. &lt;code&gt;picamera2&lt;/code&gt; pulls frames, a quantized TFLite SSD-MobileNet-v2 runs COCO object detection, and every confirmed sighting gets appended to a daily JSONL log. A read-only FastAPI service reads that log back out over my tailnet. The detector writes, the API reads, and they run as separate services so I can restart one without disturbing the other.&lt;/p&gt;
&lt;p&gt;The Zero 2 W is the bottleneck: quad A53, 512 MB, around 2 to 6 FPS for full COCO. That&amp;#39;s slow for video and plenty for &amp;quot;who or what just walked by.&amp;quot; It debounces per label, so it records presence over time instead of flooding the log every frame.&lt;/p&gt;
&lt;p&gt;It stores no video. Frames stay in memory unless I ask for them, and what lands on disk is metadata: one JSON object per detection with the label, confidence, and bounding box. There&amp;#39;s a live preview too, off by default and tailnet-only, plain MJPEG that renders into an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and encodes on the Zero 2 W&amp;#39;s hardware block instead of the CPU.&lt;/p&gt;
&lt;p&gt;The HAT writes its own stream, polling temperature, humidity, pressure, and light every thirty seconds. The board heats itself, so the temperature reads high. A live reading of the SoC temperature feeds a thermal-divider model that subtracts the self-heating and pulls the number back toward the actual room.&lt;/p&gt;
&lt;p&gt;Right now it isn&amp;#39;t doing anything. It watches my desk and writes things down. But I have ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;track my water intake during the workday&lt;/li&gt;
&lt;li&gt;turn the lights on and off depending on whether I&amp;#39;m actually at my desk&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><media:content url="https://wsrv.nl/?url=https%3A%2F%2Fblobs.farfield.systems%2Fblobs%2Fbafkreihzqgr2igbs5ggops54ad7vb5bjy6zlwnsnltb6nvzcqfegqs5gs4&amp;w=960&amp;q=80&amp;output=webp" medium="image"/><category>Posts</category><category>computer-vision</category><category>edge-computing</category><category>raspberry-pi</category><category>hardware</category><category>machine-learning</category><category>side-projects</category><category>quantified-self</category></item></channel></rss>