<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Micro-transmissions — Fred Jonsson</title>
  <subtitle>Thoughts in progress. Short notes from Fred Jonsson on building with LLMs, devtools, and whatever else is on his desk.</subtitle>
  <link href="https://fredjonsson.is/transmissions/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://fredjonsson.is/transmissions/" rel="alternate" type="text/html"/>
  <id>https://fredjonsson.is/transmissions/</id>
  <updated>2026-05-28T00:00:00.000Z</updated>
  <author>
    <name>Fred Jonsson</name>
    <uri>https://fredjonsson.is/</uri>
    <email>fred@tumbric.com</email>
  </author>
  <rights>© Fred Jonsson</rights>
  <generator uri="https://fredjonsson.is/">fredjonsson.is build</generator>
  <entry>
    <title>My relationship with computers and programming</title>
    <link href="https://fredjonsson.is/transmissions/my-relationship-with-computers-and-programming/" rel="alternate" type="text/html"/>
    <id>https://fredjonsson.is/transmissions/my-relationship-with-computers-and-programming/</id>
    <published>2026-05-28</published>
    <updated>2026-05-28</updated>
    <summary>How it all started, and the programs we met along the way.</summary>
    <content type="html"><![CDATA[
<p>My first computer was already old when it became mine. It was a Macintosh Centris 610 that my dad handed down after years of using it for CAD ventilation design. I could not really read yet, so my earliest relationship with computers was mostly exploratory: click something, see what happened, remember the result, try again.</p>

<figure>
  <img src="/assets/my-relationship-with-computers-and-programming/system-7.png" alt="A classic Macintosh System 7 desktop with overlapping windows and a grey patterned background.">
  <figcaption>Image: <a href="https://commons.wikimedia.org/wiki/File:System_7.1_on_a_emulator.png">System 7.1 on an emulator</a> by LoganDeveloper, <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>.</figcaption>
</figure>

<p>That was enough to make computers feel magical. A computer was a place where you could make something from nothing if you learned the right incantations. As I got older, I became interested in authoring anything I could make on a computer: posters, crosswords, printouts, little documents that felt official because they had been produced by a machine.</p>

<p>If I created something particularly good, I would print it on my dad's ImageWriter II. The result invariably had the creative feel of an invoice, but I was still proud of it.</p>

<figure>
  <img src="/assets/my-relationship-with-computers-and-programming/imagewriter-ii.jpeg" alt="An Apple ImageWriter II dot matrix printer.">
  <figcaption>Image: <a href="https://commons.wikimedia.org/wiki/File:Apple_ImageWriter_II.jpg">Apple ImageWriter II</a> by Blake Patterson, <a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a>.</figcaption>
</figure>

<p>That early interest in using new technology to create things followed me into adulthood. It has probably defined more of my vocation than any single course, job, or framework.</p>

<h2>The Security Era</h2>

<p>To my dad's immense misfortune, one of my first technological interests was how data could be locked down and secured. At the time, "data" mostly meant my dad's work documents and spreadsheets.</p>

<p>If there was a way to set a password on something, I would try it. Throughout my childhood I protected, encrypted, or otherwise locked down almost anything that could be locked down. Since my dad used a serious computer for work, I sometimes tried these techniques on his work computer, occasionally during the most intense of his deadlines.</p>

<p>Thankfully, he has always been patient with me. But it must have been a relief when I eventually got a computer of my own.</p>

<h2>The JavaScript.com Era</h2>

<p>I have always had a strong curiosity about computers. I have gone down many rabbit holes that will never be useful, just to understand how things work. But there was always an underlying motivation: what could I build?</p>

<p>I cared about building because I loved showing people something they didn't know was possible, or something they hadn't thought of solving in a particular way. That habit has stayed with me. I have always had a decent awareness of developer tooling and the primitives you can use to take software from prototype to production. I tend to notice what is possible now, what's about to be possible, and what you can just about make work.</p>

<p>This created a long-running tendency to collect building blocks: tools, playbooks, platforms, techniques. I get excited about each issue of the Thoughtworks Technology Radar, new cloud services, and new applications of neural models.</p>

<figure>
  <img src="/assets/my-relationship-with-computers-and-programming/javascript-com.png" alt="An archived directory page of JavaScript scripts and snippets.">
  <figcaption>Screenshot from an <a href="https://web.archive.org/web/20050908085907/http://www.scriptsearch.com/JavaScript/Scripts/">archived JavaScript scripts directory</a> via the Internet Archive.</figcaption>
</figure>

<p>But before this programming interest became "engineering", the building blocks I relied on most came from JavaScript.com. It had a large collection of snippets for various things: largely fun, mostly impractical pieces of code you could copy into your own web page to make it more interactive. They had Breakout, calendars, calculators, little toys, and many strange effects.</p>

<p>My older brothers knew what made me tick, so as a Christmas gift in the early 2000s they bestowed upon me my own domain name: frikki.com. "Frikki" is my Icelandic nickname, which I have had to drop in the Anglo world because of its unfortunate similarity to "freaky".</p>

<p>In my first real venture into interactivity and programming, I would diligently copy and translate code snippets from JavaScript.com to power the interactivity on my personal website, which I built in Microsoft Publisher 98.</p>

<figure>
  <img src="/assets/my-relationship-with-computers-and-programming/frikki-com.png" alt="An archived early-2000s personal website called Frikki.com with bright navigation buttons and a cartoonish layout.">
  <figcaption>Screenshot from <a href="https://web.archive.org/web/20020123090443/http://www.frikki.com/">archived frikki.com</a> via the Internet Archive.</figcaption>
</figure>

<p>The site had all the markings of a 13-year-old's website in 2002: a chat room, JavaScript games, links to my personal "award sites", cheat codes for SWAT 3, and dynamic forms for things too operationally important to simply go to email: guestbook, story competition, contact me.</p>

<p>The JavaScript games felt cutting edge in my circles. I did not understand much of the code, except where to find the strings I needed to translate into Icelandic and carefully encode as ISO-8859-1. But it didn't matter. I copied and pasted, and at the time that was frontier enough.</p>

<h2>The Era of Defense</h2>

<p>In the mid-2000s, the internet shifted from relatively innocent and underpowered into a more dynamic place with more interesting web services and a higher degree of danger.</p>

<p>At this stage I was doing most of my computing on Windows, and serious zero-day exploits seemed to arrive constantly. Malware was rampant, and many viruses were not caught by antivirus software.</p>

<p>This started a more serious interest in computer security. It was also the start of another information revolution: podcasts. In 2006, Steve Gibson and Leo Laporte started Security Now!, which helped me tremendously in my understanding of computers and security.</p>

<p>Steve would go into rich detail about exploits and how they used weaknesses in operating systems. But the episodes were also a great introduction to cryptography, randomness, VPNs, DoS attacks, NAT, Wi-Fi, and DRM. This was before YouTube was widely popular and years before I started college, so I owe much of my operating systems foundation to Steve and Leo.</p>

<p>But an even more significant personal shift toward defense was happening elsewhere. I had found my way to a very special chat community called Spinchat. It was not IRC, but a German proprietary chat protocol built by a few friends that seemed like they were into the Chaos Computer Club, with a web client written in Java.</p>

<figure>
  <img src="/assets/my-relationship-with-computers-and-programming/spinchat.png" alt="A small screenshot of the Spinchat chat client interface.">
  <figcaption>Screenshot from a <a href="https://okgenweb.net/helplinks/chat/spinchat_howto.htm">Spinchat how-to page</a>.</figcaption>
</figure>

<p>The chatrooms were friendly and fun, and it was my first time meeting people from all over the world. People mostly talked about day-to-day things and had a laugh with each other. But it also became my first time working hard for a promotion and climbing the proverbial ladder.</p>

<p>There were two tiers of operators in Spinchat's chatrooms: temps and perms. Temps had a blue name and could kick people out of the chatroom while they were online, but lost the power when they went offline. Perms had a red name and always had their powers, including kicking and banning IPs.</p>

<p>Being a temp was shift work, assigned when a perm was too busy to watch the channel for people swearing or "cyber". You would usually do an honest shift until you went offline, but then you might not be needed for days.</p>

<p>I became very interested in the work. I got some kind of joy out of enforcement and maintaining a happy equilibrium in the channel. So when I was opped by a perm, I was on it. I was going to do the best job I could, because one day I would become a perm.</p>

<p>Being a temp had its problems. It affected my interest in leaving the house or joining family activities, since it was my time to shine. My family appreciated my enthusiasm for technology, but they did not fully grasp that becoming a respected member of a German internet community was worth some sacrifices.</p>

<p>There were great reasons to want to become a perm. One I cherished was the freedom of the lifestyle: I could come and go as I pleased, and if a friend wanted to hang out during my tour of duty, I could take a break and come back.</p>

<p>But an even stronger motivation was the ability to maintain order. You might expect that the worst internet crimes in the mid-2000s were swearing and cybersex. But there was a more sinister force in those early chatrooms: flooders.</p>

<p>Flooders would join a room and fill it with messages so nobody else could enjoy the chat. The most egregious ones were both lewd and loud. Their relentless work to destroy a good time gave me a sense of purpose, and eventually led me to programming.</p>

<p>The initial flooders were just fast at copy-pasting, but over time they adopted programmatic tools, or "bots". Since you could only IP-ban an online user, flooders would come back and leave the server quickly enough that they could not be banned. A flood wave started, filled a screen, and finished within a second. To many ops, they were uncatchable.</p>

<p>The people who built the chat service were German and rarely seen in the English chatrooms. I had grave concerns about the flooding situation, and one day I was lucky enough that someone introduced me to a Multi User Dungeon that served as the hangout for these lords of chat, mostly conversing in German.</p>

<figure>
  <img src="/assets/my-relationship-with-computers-and-programming/mud.png" alt="A terminal-style Multi User Dungeon map and room description.">
  <figcaption>Image: <a href="https://commons.wikimedia.org/wiki/File:Actsmudgnome.png">GnomeMUD screenshot</a> by Zeth, <a href="http://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA 3.0</a>.</figcaption>
</figure>

<p>Multi User Dungeons were the metaverse of the terminal age. You moved between rooms and chatted with people, with a map drawn in ASCII. If you were in the same room as someone else, you could talk. There were probably many secrets in those dungeons, but I don't think I went far beyond the lobby.</p>

<p>I pleaded with the owners about moderation on the international side of the web site (in contrast to the prudently moderated German one), and in particular about flooders. I had come across unsanctioned documentation for their proprietary protocol, and in my effort to see if I could build a bot I had some success using Telnet to connect to their servers, join rooms, and send messages. The protocol was terse and cryptic, and I had no real programming experience to build with it.</p>

<p>I don't know what led to it: my incessant pestering, the desire to empower someone to solve the problem, or the kindness of an experienced tinkerer helping a teenager take his first steps with programming. But one of the owners gave me a Perl socket library and a scaffold to connect to the servers and send and receive messages. That was enough to start a long road fighting flooders.</p>

<p>And thus began my first programming project: Thunder, a flood-fighting bot incarnated as a long spaghetti Perl script and later elevated with features like hugging and poking back, so it could behave reciprocally when someone typed <code>/me pokes Thunder</code>.</p>

<p>As it was, the war with the flooders was unwinnable. As our techniques got more advanced, so did theirs. Although the fight was adversarial, the stakes were low. Flooders were an annoyance, but nobody was harmed, and as determined as I felt about ensuring an uninterrupted chat experience, I never felt much animosity toward them. If anything, they were a good challenge.</p>

<p>When I eventually ended my Spinchat chapter in my later teenage years, what remained was a new love for programming.</p>
    ]]></content>
    <category term="programming"/>
    <category term="history"/>
    <author><name>Fred Jonsson</name></author>
  </entry>
  <entry>
    <title>Agents and the shape of work</title>
    <link href="https://fredjonsson.is/transmissions/agents-and-the-shape-of-work/" rel="alternate" type="text/html"/>
    <id>https://fredjonsson.is/transmissions/agents-and-the-shape-of-work/</id>
    <published>2026-02-10</published>
    <updated>2026-02-10</updated>
    <summary>Agents are inevitable. The relationship we want with them is not. A sketch of a workplace designed to preserve our energy and clarity.</summary>
    <content type="html"><![CDATA[
<p>We have some work to do together as a tech industry. Agents are inevitable, and we need to design the relationship we want to have with them.</p>

<p>Many early adopters of agents, including myself, have started to feel the urge to have many agents running in parallel and to always keep them occupied.</p>

<p>This is not a new desire at work — we all organize our work to happen efficiently. But now, the number of work items that can be happening in parallel is becoming practically unbounded.</p>

<p>On top of this comes an added burden of context-switching. Today, the experience involves agents coming back to you with results across many different applications — Claude, Cursor, Codex, and ChatGPT. Of course, you still have Slack, e-mail, and texts to attend to.</p>

<p>We are, of course, in the early days and on the leading edge, and right now the edge is sharp. But seeing where we're going should lead us to think about how we want things to be, so we can stop messy ways of working from lingering.</p>

<p>The risk is that we move fast on tasks at the cost of our judgement and perspective. That we become efficient but not effective, and robbed of our clarity and calm.</p>

<p>If we think about our future through the lenses of user experience and human-computer interface design, we are hopefully compelled to think beyond another conversational interface.</p>

<p>Instead, we would consider:</p>

<ul>
  <li><strong>cognitive aspects</strong>, like context switching</li>
  <li><strong>psychological aspects</strong>, like need for achievement</li>
  <li><strong>convenience aspects</strong>, like using a tablet with voice</li>
</ul>

<p>Courtesy of Claude, here's a sketch of what such a workplace should look like:</p>

<figure>
  <img src="/assets/agents-and-the-shape-of-work/sketch.jpeg" alt="A four-tab workplace interface called Current, showing Clarity, Focus, Chat, and Fleet tabs. The current view lists tasks needing attention, an agent activity banner noting items resolved overnight, and a Voice Stories v2 project timeline with on-track, at-risk, and blocked workstreams.">
</figure>

<ul>
  <li>one tab to gain <strong>clarity</strong> — progress, plans, problems</li>
  <li>one tab for <strong>focused work</strong> — review, research, read</li>
  <li>one tab for <strong>conversation</strong> — with agents and humans</li>
  <li>one tab for <strong>fleet</strong> — to see how agents are progressing</li>
</ul>

<p>This is a simplification of a complex problem. But it illustrates what I hope is the future — a workplace designed to be productive and enjoyable, designed from first principles.</p>

<p>Whether it will be a product like Slack or something that many companies evolve internally, the best productivity tool of the next decade is going to be the one that best preserves our energy and clarity.</p>
    ]]></content>
    <category term="agents"/>
    <category term="design"/>
    <author><name>Fred Jonsson</name></author>
  </entry>
  <entry>
    <title>Prevent &gt; Detect &gt; Document</title>
    <link href="https://fredjonsson.is/transmissions/prevent-detect-document/" rel="alternate" type="text/html"/>
    <id>https://fredjonsson.is/transmissions/prevent-detect-document/</id>
    <published>2026-01-27</published>
    <updated>2026-01-27</updated>
    <summary>We focus a lot on rules, but the codebase itself is a key way to safer changes with coding agents. Three questions to ask of every agent bug — and why prevention wins.</summary>
    <content type="html"><![CDATA[
<p>The coding agents discussion is dominated by a focus on rules and skills, and we often neglect the role of the codebase itself on the road to safer agent tasks.</p>

<p>You have three main ways to reduce the odds of bugs in a codebase:</p>

<ul>
  <li><strong>Document</strong> — write "don't do X" in dev docs or agent rules.</li>
  <li><strong>Detect</strong> — add tests and lints to catch mistakes after they're written.</li>
  <li><strong>Prevent</strong> — design interfaces to make wrong code impossible.</li>
</ul>

<p>Prevention (or <em>possibility reduction</em>) is the principle that if you want to avoid a class of bug, you make that bug impossible to create. Testing does not achieve impossibility, because you can forget to write the test.</p>

<p>You can achieve this through different methods — strict typing, abstractions that make footguns private, even formal methods. The most basic example: if you have a switch-statement, it should be impossible to miss a case. Languages with rich type systems help a lot.</p>

<p>Agents, like humans, are prone to missing steps. They'll change a string in one place and forget to change it in another. But unlike humans, they don't know to be extra careful in the most critical parts of your code.</p>

<p>So I now try to ask these three questions for every agent bug:</p>

<ol>
  <li>Can I prevent this class of bug at compile time? If no…</li>
  <li>Can I detect it at test time? If no…</li>
  <li>Can I document it well, and detect it when it fails in production?</li>
</ol>

<p>When you put it like that, it's pretty obvious which one you don't want. If you've spent time in incident postmortems and maintained systems over a long time, you're rehearsed in this thinking.</p>

<p>But one thing is changing: prevention was historically a lot more expensive than detection, but there are now many cases where that's no longer true, particularly because large-scale migrations to safer abstractions can be orchestrated by agents.</p>

<p>Some recent examples of things I've done to apply this in practice in Tumbric's evaluation and training codebase:</p>

<ul>
  <li><strong>Ideally Rust, (almost) never Bash.</strong> I'll use Python or TypeScript is if it's essential for the use case. Everything else is in Rust.</li>
  <li><strong>Typed state machines for workflows.</strong> In event handlers, transitions to illegal states are prevented at compile time.</li>
  <li><strong>Predicated events.</strong> The API for processing events forces events, at the type level, to declare the state they were predicated on, so version conflicts can be detected systematically.</li>
</ul>

<figure class="code-compare-figure">
  <div class="code-compare" aria-label="Before and after state transition typing">
    <section class="code-panel before" aria-labelledby="transition-before">
      <div class="code-panel-head">
        <span class="code-panel-label" id="transition-before">Before</span>
        <span class="code-panel-note">any destination is accepted</span>
      </div>
<pre><code class="language-ts syntax-ts"><span class="tok-comment">// transition accepts any string</span>
<span class="tok-keyword">type</span> <span class="tok-type">Run</span> <span class="tok-op">=</span> { <span class="tok-prop">status</span>: <span class="tok-type">string</span> };

<span class="tok-keyword">function</span> <span class="tok-fn">transition</span>(
  <span class="tok-name">run</span>: <span class="tok-type">Run</span>,
  <span class="tok-name">to</span>: <span class="tok-type">string</span>
): <span class="tok-type">Run</span> {
  <span class="tok-keyword">return</span> { ...<span class="tok-name">run</span>, <span class="tok-prop">status</span>: <span class="tok-name">to</span> };
}

<span class="tok-fn">transition</span>({ <span class="tok-prop">status</span>: <span class="tok-string">'pending'</span> }, <span class="tok-string">'executing'</span>);  <span class="tok-comment">// <span class="tok-ok">OK</span></span>
<span class="tok-fn">transition</span>({ <span class="tok-prop">status</span>: <span class="tok-string">'pending'</span> }, <span class="tok-string">'completed'</span>);  <span class="tok-comment">// <span class="tok-warn">compiles, bug ships</span></span>
</code></pre>
    </section>

    <section class="code-panel after" aria-labelledby="transition-after">
      <div class="code-panel-head">
        <span class="code-panel-label" id="transition-after">After</span>
        <span class="code-panel-note">destination follows current status</span>
      </div>
<pre><code class="language-ts syntax-ts"><span class="tok-comment">// destination comes from the current status</span>
<span class="tok-keyword">const</span> <span class="tok-name">next</span> <span class="tok-op">=</span> {
  <span class="tok-prop">pending</span>:   [<span class="tok-string">'executing'</span>],
  <span class="tok-prop">executing</span>: [<span class="tok-string">'completed'</span>, <span class="tok-string">'failed'</span>],
  <span class="tok-prop">completed</span>: [],
  <span class="tok-prop">failed</span>:    [<span class="tok-string">'pending'</span>],
} <span class="tok-keyword">as const</span>;

<span class="tok-keyword">type</span> <span class="tok-type">Status</span> <span class="tok-op">=</span> <span class="tok-keyword">keyof typeof</span> <span class="tok-name">next</span>;
<span class="tok-keyword">type</span> <span class="tok-type">Next</span>&lt;<span class="tok-type">From</span> <span class="tok-keyword">extends</span> <span class="tok-type">Status</span>&gt; <span class="tok-op">=</span>
  (<span class="tok-keyword">typeof</span> <span class="tok-name">next</span>)[<span class="tok-type">From</span>][<span class="tok-type">number</span>];

<span class="tok-keyword">function</span> <span class="tok-fn">transition</span>&lt;<span class="tok-type">From</span> <span class="tok-keyword">extends</span> <span class="tok-type">Status</span>&gt;(
  <span class="tok-name">run</span>: { <span class="tok-prop">status</span>: <span class="tok-type">From</span> },
  <span class="tok-name">to</span>: <span class="tok-type">Next</span>&lt;<span class="tok-type">From</span>&gt;
) {
  <span class="tok-keyword">return</span> { ...<span class="tok-name">run</span>, <span class="tok-prop">status</span>: <span class="tok-name">to</span> };
}

<span class="tok-fn">transition</span>({ <span class="tok-prop">status</span>: <span class="tok-string">'pending'</span> }, <span class="tok-string">'executing'</span>);  <span class="tok-comment">// <span class="tok-ok">OK</span></span>
<span class="tok-fn">transition</span>({ <span class="tok-prop">status</span>: <span class="tok-string">'pending'</span> }, <span class="tok-string">'completed'</span>);  <span class="tok-comment">// <span class="tok-error">compile error</span></span>
</code></pre>
    </section>
  </div>
<figcaption>The API stays simple: callers pass the run and the destination, but invalid destinations stop compiling.</figcaption>
</figure>

<p>The kind of serious investment I used to put into the reliability of payments systems is now something I'm putting into a "casual" internal system to track training runs. That's because the cost of adding strictness is now very low, the added friction is imperceptible, and the benefits are enduring.</p>

<p>It doesn't matter how fast the agent can code. We can't move fast without safety. So simplifying systems, adding strictness, and making error states impossible is a core human engineering activity in a world where agents do more of the implementation work.</p>
    ]]></content>
    <category term="agents"/>
    <category term="engineering"/>
    <author><name>Fred Jonsson</name></author>
  </entry>
  <entry>
    <title>Your devtools SaaS is now an API company</title>
    <link href="https://fredjonsson.is/transmissions/you-are-now-an-api-company/" rel="alternate" type="text/html"/>
    <id>https://fredjonsson.is/transmissions/you-are-now-an-api-company/</id>
    <published>2026-01-26</published>
    <updated>2026-01-26</updated>
    <summary>If you&#39;re building devtools, your primary DX surface is now for agents. Polished SDKs and beautiful UIs are becoming secondary interfaces.</summary>
    <content type="html"><![CDATA[
<p>I saw a devtools CTO recently complaining about "programmer brainrot" and how engineers no longer read docs.</p>

<p>It's never been a good use of developer time to study SaaS APIs. Field-level API details of a third-party product are a small and unleveraged part of an engineer's job, and this is becoming much truer with coding agents.</p>

<p>I regularly ask agents to integrate with SaaS tools. The agent flails for 30 minutes, hits some 500 errors, and gives up eventually because it needs information that's only available through the UI. I switch to a simpler product (often one with a good <code>llms.txt</code>), and integration takes 5 minutes with an agent.</p>

<p>The reality is that if you're building devtools, polished SDKs and beautiful UIs are becoming secondary interfaces and you're now an API company.</p>

<p>What this means:</p>

<ul>
  <li>If there's a button in your console, it needs to be an API operation.</li>
  <li>If your product ingests or produces data, there needs to be an API to export it.</li>
  <li>If you're seeing people hit edge cases in Sentry, expect 10x more in 6 months.</li>
</ul>

<p>Your primary DX surface is now for agents. The good news is that you can literally just run a test suite against it. And if you do it well, you can ease up on pixel-perfect and concise docs — developers will probably just ask Claude about your product anyway.</p>

<p>Mass adoption of coding agents is still early but things are moving fast. So now's a great time to become the best product for agents in your space.</p>
    ]]></content>
    <category term="agents"/>
    <category term="devtools"/>
    <author><name>Fred Jonsson</name></author>
  </entry>
</feed>
