<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://kevinlynagh.com/">
  <id>https://kevinlynagh.com/</id>
  <title>Kevin Lynagh's website</title>
  <updated>2026-04-20T00:00:00Z</updated>
  <link rel="alternate" href="https://kevinlynagh.com/" type="text/html"/>
  <link rel="self" href="https://kevinlynagh.com/feed.xml" type="application/atom+xml"/>
  <author>
    <name>Kevin Lynagh</name>
    <uri>https://kevinlynagh.com</uri>
  </author>
  <entry>
    <id>tag:kevinlynagh.com,2026-04-20:/newsletter/2026_04_overthinking/</id>
    <title type="html">On sabotaging projects by overthinking, scope creep, and structural diffing</title>
    <published>2026-04-20T00:00:00Z</published>
    <updated>2026-04-20T00:00:00Z</updated>
    <link rel="alternate" href="https://kevinlynagh.com/newsletter/2026_04_overthinking/" type="text/html"/>
    <content type="html">&lt;p&gt;Hi friends,&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll be attending &lt;a href="https://babashka.org/conf/"&gt;Babashka Conf&lt;/a&gt; on May 8 and &lt;a href="https://clojuredays.org/"&gt;Dutch Clojure Days&lt;/a&gt; on May 9.
If you&amp;rsquo;re attending either (or just visiting Amsterdam), drop me a line!&lt;/p&gt;
&lt;h2 id='on-sabotaging-projects-by-overthinking'&gt;&lt;a class='anchor' href='#on-sabotaging-projects-by-overthinking'&gt;On sabotaging projects by overthinking&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When I have an idea for a project, it tends to go in one of these two directions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I just do it. Maybe I make a few minor revisions, but often it turns out exactly how I&amp;rsquo;d imagined and I&amp;rsquo;m happy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I think, &amp;ldquo;I should look for prior art&amp;rdquo;. There&amp;rsquo;s a lot of prior art, dealing with a much broader scope than I&amp;rsquo;d originally imagined. I start to wonder if I should incorporate that scope. Or perhaps try to build my thing on top of the existing sorta-nearby-solutions. Or maybe I should just use the popular thing. Although I could do a better job than that thing, if I put a bunch of time into it. But actually, I don&amp;rsquo;t want to maintain a big popular project, nor do I want to put that much time into this project. Uh oh, now I&amp;rsquo;ve spent a bunch of time, having neither addressed the original issue nor experienced the joy of creating something.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I prefer the first outcome, and I think the pivotal factor is how well I&amp;rsquo;ve internalized my own success criteria.&lt;/p&gt;

&lt;p&gt;For example, last weekend I hosted my friend Marcin and we decided it&amp;rsquo;d be fun to do some woodworking, so we threw together this shelf and 3d-printed hangers for my kitchen:&lt;/p&gt;

&lt;p&gt;&lt;img src="shelf.jpg" alt="a black shelf with a painted orange/pink edge and Ikea food bins hanging off the bottom"&gt;&lt;/p&gt;

&lt;p&gt;Absolute banger of a project: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;brainstormed the design over coffee&lt;/li&gt;
&lt;li&gt;did a few 3d-print iterations for the Ikea bin hangers (&lt;a href="https://cad.onshape.com/documents/ffd05cea283ba8ac162ddde1/w/f63670037dee41f664a23b76/e/4258465c9a6965b596cb054b"&gt;OnShape CAD&lt;/a&gt;, if you want to print your own)&lt;/li&gt;
&lt;li&gt;used material leftover from &lt;a href="/newsletter/2026_01_tools/#workshop-space"&gt;my workbench&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;rounded the corner by eye with a palm sander&lt;/li&gt;
&lt;li&gt;sealed the raw plywood edge with some leftover paint from a friend&lt;/li&gt;
&lt;li&gt;done in a weekend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main success criteria was to jam on woodworking with a friend, and that helped me not overthink the object-level success criteria: Just make a shelf for my exact kitchen!&lt;/p&gt;

&lt;p&gt;In contrast, this past Friday I noticed &lt;a href="https://github.com/Wilfred/difftastic/"&gt;difftastic&lt;/a&gt; did a poor job, so I decided to shop around for structural/semantic diff tools and related workflows (a topic I&amp;rsquo;ve never studied, that I&amp;rsquo;m increasingly interested in as I&amp;rsquo;m reviewing more and more LLM-generated code).&lt;/p&gt;

&lt;p&gt;I spent 4 hours over the weekend researching existing tools (see &lt;a href="#structural-diffing"&gt;my notes below&lt;/a&gt;), going through dark periods of both &amp;ldquo;semantic tree diffing is a PhD-level complex problem&amp;rdquo; and &amp;ldquo;why do all of these have MCP servers? I don&amp;rsquo;t want an MCP server&amp;rdquo;, before I came to my senses and remembered my original success criteria: I just want a nicer diffing workflow for myself in Emacs, I should just build it myself &amp;mdash; should take about 4 hours.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m cautiously optimistic that, having had this realization and committing myself to a minimal scope, I&amp;rsquo;ll be able to knock out a prototype before running out of motivation.&lt;/p&gt;

&lt;p&gt;However, other long-running interests of mine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interfaces for prototyping hardware (discussed &lt;a href="/newsletter/2023_09_hardware_prototyping/#interfaces-for-prototyping-hardware"&gt;September 2023&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;a programming language that fuses what I like about Clojure and Rust (&lt;a href="/newsletter/2023_11_programming_languages/"&gt;November 2023&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;a programming language for CAD (&lt;a href="/newsletter/2025_10_bed/#a-simple-constraint-language"&gt;constraints&lt;/a&gt;, &lt;a href="/newsletter/2025_07_flatpack/#lsp-bidirectional-editing-cad-conceptual-models"&gt;bidirectional editing&lt;/a&gt;, &lt;a href="/newsletter/2025_04_towards_the_cutest_neural_network/#dubious-ideas-for-a-code-cad-language"&gt;other dubious ideas&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;seem to be deep in the well of outcome #2.&lt;/p&gt;

&lt;p&gt;That is, I&amp;rsquo;ve spent hundreds of hours on background research and little prototypes, but haven&amp;rsquo;t yet synthesized anything that addresses the original motivating issue.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s not quite that I &lt;em&gt;regret&lt;/em&gt; that time &amp;mdash; I do love learning by reading &amp;mdash; but I have a nagging sense of unease that my inner critic (fear of failure?) is silencing my generative tendencies, keeping me from the much more enjoyable (and productive!) learning by &lt;em&gt;doing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I think in these cases the success criteria has been much fuzzier: Am I trying to replace my own usage of Rust/Clojure?
Only for some subset of problems?
Or is it that I actually just need a playground to learn about language design/implementation, and it&amp;rsquo;s fine if I don&amp;rsquo;t end up using it?&lt;/p&gt;

&lt;p&gt;Ditto for CAD: Am I trying to replace my commercial CAD tool in favor of my own?
Only for some subset of simple or particularly parametric parts?
Do I care if it&amp;rsquo;s useful for others?
Does my tool need to be legibly different from existing open-source tools?&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s worth considering these questions, sure.
But at the end of the day, I&amp;rsquo;d much rather have &lt;em&gt;done&lt;/em&gt; a lot than have only &lt;em&gt;considered&lt;/em&gt; a lot.&lt;/p&gt;

&lt;p&gt;So I&amp;rsquo;m trying to embrace my inner clueless 20-year-old and &lt;em&gt;just do things&lt;/em&gt; &amp;mdash; even if some turn out to be &amp;ldquo;obviously bad&amp;rdquo; in hindsight, I&amp;rsquo;ll still be coming out ahead on net =D&lt;/p&gt;
&lt;h2 id='conservation-of-scope-creep'&gt;&lt;a class='anchor' href='#conservation-of-scope-creep'&gt;Conservation of scope creep&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Of course, there&amp;rsquo;s only so much time to &amp;ldquo;just do things&amp;rdquo;, and there&amp;rsquo;s a balance to be had. I&amp;rsquo;m not sure how many times I&amp;rsquo;ll re-learn YAGNI (&amp;ldquo;you ain&amp;rsquo;t gonna need it&amp;rdquo;) in my career, but I was reminded of it again after writing a bunch of code with an LLM agent, then eventually coming to my senses and throwing it all out.&lt;/p&gt;

&lt;p&gt;I wanted a &lt;a href="https://keminglabs.com/finda/"&gt;Finda&lt;/a&gt;-style filesystem-wide fuzzy path search for Emacs.
Since I&amp;rsquo;ve built (by hand, typing the code myself!) this exact functionality before (walk filesystem to collect paths, index them by trigram, do fast fuzzy queries via bitmap intersections), I figured it&amp;rsquo;d only take a few hours to supervise an LLM to write all the code.&lt;/p&gt;

&lt;p&gt;I started with a &amp;ldquo;plan mode&amp;rdquo; chat, and the LLM suggested a library, &lt;a href="https://github.com/helix-editor/nucleo"&gt;Nucleo&lt;/a&gt;, which turned up since I wrote Finda (10 years ago, eek!).
I read through it, found it quite well-designed and documented, and decided to use it so I&amp;rsquo;d get its smart case and Unicode normalization functionality.
(E.g., query &lt;code&gt;foo&lt;/code&gt; matches &lt;code&gt;Foo&lt;/code&gt; and &lt;code&gt;foo&lt;/code&gt;, whereas query &lt;code&gt;Foo&lt;/code&gt; &lt;em&gt;won&amp;rsquo;t&lt;/em&gt; match &lt;code&gt;foo&lt;/code&gt;; similarly for &lt;code&gt;cafe&lt;/code&gt; and &lt;code&gt;café&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;Finding a great library wasn&amp;rsquo;t the problem, the problem was that Nucleo also supported some extra functionality: anchors (&lt;code&gt;^foo&lt;/code&gt; only matches at the beginning of a line).&lt;/p&gt;

&lt;p&gt;This got me thinking about what that might mean in a corpus that consists entirely of file paths.
Anchoring to the beginning of a line isn&amp;rsquo;t useful (everything starts with &lt;code&gt;/&lt;/code&gt;), so I decided to try and interpret the anchors with respect to the path &lt;em&gt;segments&lt;/em&gt;.
E.g., &lt;code&gt;^foo&lt;/code&gt; would match &lt;code&gt;/root/foobar/&lt;/code&gt; but not &lt;code&gt;/root/barfoo/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But to do this efficiently, the index needs to keep track of segment boundaries so that the query can be checked against each segment quickly.&lt;/p&gt;

&lt;p&gt;But then we &lt;em&gt;also&lt;/em&gt; need to handle a slash occurring in an anchored query (e.g., &lt;code&gt;^foo/bar&lt;/code&gt;) since that wouldn&amp;rsquo;t get matched when only looking at segments individually (&lt;code&gt;root&lt;/code&gt;, &lt;code&gt;foo&lt;/code&gt;, &lt;code&gt;bar&lt;/code&gt;, and &lt;code&gt;baz&lt;/code&gt; of a matching path &lt;code&gt;/root/foo/bar/baz/&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Working through this took several hours: first throwing around design ideas with an LLM, having it write code to wrap Nucleo&amp;rsquo;s types, then realizing its code was bloated and didn&amp;rsquo;t spark joy, so finally writing my own (smaller) wrapper.&lt;/p&gt;

&lt;p&gt;Then, after a break, I realized:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I can&amp;rsquo;t think of a situation where I&amp;rsquo;d ever wished Finda had anchor functionality&lt;/li&gt;
&lt;li&gt;In a corpus of paths, I can anchor by just adding &lt;code&gt;/&lt;/code&gt; to the start or end of a query (this works for everything except anchoring to the end of a filename).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I tossed all of the anchoring code.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m &lt;em&gt;pretty&lt;/em&gt; sure I still came out ahead compared to if I&amp;rsquo;d tried to write everything myself sans LLM or discussion with others, but I&amp;rsquo;m not certain.&lt;/p&gt;

&lt;p&gt;Perhaps there&amp;rsquo;s some kind of conservation law here: Any increases in programming speed will be offset by a corresponding increase in unnecessary features, rabbit holes, and diversions.&lt;/p&gt;
&lt;h2 id='structural-diffing'&gt;&lt;a class='anchor' href='#structural-diffing'&gt;Structural diffing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Speaking of unnecessary diversions, let me tell you everything I&amp;rsquo;ve learned about structural diffing recently &amp;mdash; if you have thoughts/feelings/references in this space, I&amp;rsquo;d love to hear about &amp;lsquo;em!&lt;/p&gt;

&lt;p&gt;When we&amp;rsquo;re talking about code, a &amp;ldquo;diff&amp;rdquo; usually means a summary of the line-by-line changes between two versions of a file.
This might be rendered as a &amp;ldquo;unified&amp;rdquo; view, where changed lines are prefixed with &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; to indicate whether they&amp;rsquo;re additions or deletions.
For example:&lt;/p&gt;

&lt;p&gt;&lt;img src="unified.png" alt=""&gt;&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ve removed &lt;code&gt;coffee&lt;/code&gt; and added &lt;code&gt;apple&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same diff might also be rendered in a side-by-side view, which can be easier to read when there are more complex changes:&lt;/p&gt;

&lt;p&gt;&lt;img src="side_by_side.png" alt=""&gt;&lt;/p&gt;

&lt;p&gt;The problem with these line-by-line diffs is that they&amp;rsquo;re not aware of higher-level structure like functions, types, etc. &amp;mdash; if some braces match up &lt;em&gt;somehow&lt;/em&gt; between versions, they might not be shown at all, even if the braces &amp;ldquo;belong&amp;rdquo; to different functions.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a wonderful tool, &lt;a href="https://github.com/Wilfred/difftastic/"&gt;difftastic&lt;/a&gt;, which tries to address this by calculating diffs using &lt;a href="https://tree-sitter.github.io/"&gt;treesitter&lt;/a&gt;-provided concrete syntax trees.
It&amp;rsquo;s a huge improvement over line-based diffs, but unfortunately it doesn&amp;rsquo;t always do a great job matching entities between versions.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the diff that motivated this entire foray:&lt;/p&gt;

&lt;p&gt;&lt;img src="difftastic.png" alt=""&gt;&lt;/p&gt;

&lt;p&gt;Note that it doesn&amp;rsquo;t match up &lt;code&gt;struct PendingClick&lt;/code&gt;, it shows it deleted on the left and added on the right.&lt;/p&gt;

&lt;p&gt;I haven&amp;rsquo;t dug into &lt;em&gt;why&lt;/em&gt; difftastic fails to match here, but I do feel like it&amp;rsquo;s wrong &amp;mdash; even if the overall diff would be longer, I&amp;rsquo;d still rather see &lt;code&gt;PendingClickRequest&lt;/code&gt; and &lt;code&gt;PendingClick&lt;/code&gt; matched up between both sides.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a summary of tools / references in the space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The most &amp;ldquo;baked&amp;rdquo; and thoughtful semantic diff tool I found is, perhaps unsurprisingly, &lt;a href="https://semanticdiff.com/blog/semanticdiff-vs-difftastic/"&gt;semanticdiff.com&lt;/a&gt;, a small German company with a free VSCode plugin and &lt;a href="https://app.semanticdiff.com/"&gt;web app that shows diffs for github PRs&lt;/a&gt;. Unfortunately they don&amp;rsquo;t have any code libraries I can use as a foundation for the workflow I want.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;this &lt;a href="https://semanticdiff.com/blog/semanticdiff-vs-difftastic/"&gt;semanticdiff vs. difftastic&lt;/a&gt; blog post covers a lot of great details (including that difftastic &lt;a href="https://github.com/Wilfred/difftastic/issues/587"&gt;doesn&amp;rsquo;t even show semantically meaningful indentation changes in python&lt;/a&gt; !!!)&lt;/li&gt;
&lt;li&gt;one of the authors has great HN comments with hard-won background knowledge. E.g., they &lt;a href="https://news.ycombinator.com/item?id=42094842"&gt;moved away from treesitter&lt;/a&gt; because it&amp;rsquo;s unreliable for semantics:&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Context-sensitive keywords in particular were a constant source of annoyance. The grammar looks correct, but it will fail to parse because of the way the lexer works. You don&amp;rsquo;t want your tool to abort just because someone named their parameter &amp;ldquo;async&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/afnanenayet/diffsitter"&gt;diffsitter&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;built on treesitter, has MCP server. README includes list of similar projects.&lt;/li&gt;
&lt;li&gt;lots of github stars, but doesn&amp;rsquo;t seem particularly well-documented; I couldn&amp;rsquo;t find an explanation of how it works, but the difftastic wiki says it &amp;ldquo;runs longest-common-subsequence on the leaves of the tree&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/GumTreeDiff/gumtree"&gt;gumtree&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;research / academic origin in 2014&lt;/li&gt;
&lt;li&gt;requires Java, so no-go for my use case of a quick tool I can use via Emacs&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://mergiraf.org/architecture.html"&gt;mergiraf&lt;/a&gt;: treesitter-based merge-driver written in rust&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mergiraf.org/architecture.html"&gt;very nice architecture overview&lt;/a&gt;; tool uses Gumtree algorithm&lt;/li&gt;
&lt;li&gt;docs and adorable illustrations indicate this project was clearly written by a thoughtful human&lt;/li&gt;
&lt;li&gt;semanticdiff.com author in &lt;a href="https://news.ycombinator.com/item?id=42094842"&gt;HN comments&lt;/a&gt;:
&amp;gt; GumTree is good at returning a result quickly, but there are quite a few cases where it always returned bad matches for us, no matter how many follow-up papers with improvements we tried to implement. In the end we switched over to a dijkstra based approach that tries to minimize the cost of the mapping&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Ataraxy-Labs/weave"&gt;weave&lt;/a&gt;: also a treesitter-based merge-driver written in Rust&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;feels a bit &amp;ldquo;HN-optimized&amp;rdquo; (flashy landing pages, lots of github stars, MCP server, etc.)&lt;/li&gt;
&lt;li&gt;I looked into their entity extraction crate, &lt;a href="https://github.com/Ataraxy-Labs/sem"&gt;sem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;core diffing code is OK but pretty wordy&lt;/li&gt;
&lt;li&gt;greedy entity matching algorithm&lt;/li&gt;
&lt;li&gt;data model can&amp;rsquo;t detect intra-file moves, even though those might be significant&lt;/li&gt;
&lt;li&gt;includes a lot of heuristic &amp;ldquo;impact&amp;rdquo; analysis, which feels like overreaching-scope to me since it&amp;rsquo;d require much tighter language integration before I&amp;rsquo;d trust it

&lt;ul&gt;
&lt;li&gt;ran into buggy output when running &lt;code&gt;sem diff --verbose HEAD~4&lt;/code&gt;; it showed lines as having changed that&amp;hellip;didn&amp;rsquo;t change at all.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Too much 80%-done, hypothetically useful functionality for me to use as a foundation, but props for sure to the undergrad/student(?) who&amp;rsquo;s built all this in just three months.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/codinuum/diffast"&gt;diffast&lt;/a&gt;: tree edit-distance of ASTs based on an algorithm from a 2008 academic paper.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;supports &amp;ldquo;Python, Java, Verilog, Fortran, and C/C++ via dedicated parsers&amp;rdquo;&lt;/li&gt;
&lt;li&gt;has a nice &lt;a href="https://codinuum.github.io/gallery-cca/"&gt;gallery of example AST differences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;can export info in tuples for datalog&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://fazzone.github.io/autochrome.html"&gt;autochrome&lt;/a&gt;: Clojure-specific diffs based on dynamic programming&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;excellent visual explanation and example walkthrough&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tristan Hume has a great article on &lt;a href="https://thume.ca/2017/06/17/tree-diffing/"&gt;Designing a Tree Diff Algorithm Using Dynamic Programming and A*&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My primary use case is reviewing LLM output turn-by-turn &amp;mdash; I&amp;rsquo;m very much in-the-loop, and I&amp;rsquo;m not letting my agent (or dozens of them, lol) run wild generating 10k+ lines of code at a time.&lt;/p&gt;

&lt;p&gt;Rather, I give an agent a scoped task, then come back in a few minutes and want to see an overview of what it did and then either revise/tweak it manually in Emacs or throw the whole thing out and try again (or just write it myself).&lt;/p&gt;

&lt;p&gt;The workflow I want, then, is to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see a high-level overview of the diff: what entities (types/functions/methods) were added/removed/changed?&lt;/li&gt;
&lt;li&gt;quickly see textual diffs on an entity-by-entity basis (&amp;ldquo;expanding&amp;rdquo; parts of the above summary)&lt;/li&gt;
&lt;li&gt;quickly edit any changes, without having to navigate elsewhere (i.e., do it inline, rather than having to switch from &amp;ldquo;diff&amp;rdquo; to &amp;ldquo;file)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, I want something like &lt;a href="https://magit.vc/screenshots/#staging-changes"&gt;Magit&amp;rsquo;s workflow for reviewing and staging changes&lt;/a&gt;, but on an entity level rather than file/line level.&lt;/p&gt;

&lt;p&gt;In light of the &amp;quot;minimal scope, just get your project done&amp;rdquo; lesson I&amp;rsquo;ve just re-learned for the nth time, my plan is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;throw together my own treesitter-based entity extraction framework (just Rust for now)&lt;/li&gt;
&lt;li&gt;do some simple greedy matching for now&lt;/li&gt;
&lt;li&gt;render the diff to the command line&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once that seems reasonable (i.e., it does a better job than difftastic did on that specific commit), I&amp;rsquo;ll:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wire into a more interactive Magit-like Emacs workflow (maybe I can reuse Magit itself!?!)&lt;/li&gt;
&lt;li&gt;add support for new languages, as I need them&lt;/li&gt;
&lt;li&gt;potentially explore more sophisticated score-based global matching rather than simple greedy matching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Mayyybe&lt;/em&gt; if I&amp;rsquo;m happy with it I&amp;rsquo;ll end up releasing something.
But I&amp;rsquo;m not trying to collect Github stars or HN karma, so I might just happily use it in the privacy of my own home without trying to &amp;ldquo;commercialize it&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;After all, sometimes I just want a shelf.&lt;/p&gt;
&lt;h2 id='misc-stuff'&gt;&lt;a class='anchor' href='#misc-stuff'&gt;Misc. stuff&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I&amp;rsquo;m in the market for a few square meters of Tyvek or other translucent, non-woven material suitable for building a light diffuser &amp;mdash; let me know if you have any favorite vendors that can ship to the EU.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=zzpLW3PdNEg"&gt;How They Made This - Coinbase Commercial Breakdown&lt;/a&gt;. Crypto is a negative-sum parasite on productive economic activity, but has the silver lining of funneling a lot of capital to weird creative folks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.mattkeeter.com/blog/2026-04-05-tailcall/"&gt;A tail-call interpreter in (nightly) Rust&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=Y_CwRw0VJ-U"&gt;The Easiest Way To Design Furniture&amp;hellip;&lt;/a&gt;. Laura Kampf on getting off the computer and designing physical spaces with tape, lil&amp;rsquo; wood sticks, and cardboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=gf6v59c5yuY"&gt;Hotel California - Reimagined on the Traditional Chinese Guzheng&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://spawn-queue.acm.org/doi/pdf/10.1145/3212477.3212479"&gt;C is &lt;em&gt;not&lt;/em&gt; a low-level language&lt;/a&gt;: Your computer is not a fast PDP-11.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.calebleak.com/posts/dog-game/"&gt;I Taught My Dog to Vibe Code Games - Caleb Leak&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://campedersen.com/loon"&gt;Loon is a Lisp&lt;/a&gt;. Thrilled to discover I&amp;rsquo;m not the only one who wants to mash together Clojure and Rust. The current implementation seems to have been manically vibe-coded and I quickly ran into some terrible bugs, but on the other hand it &lt;em&gt;exists&lt;/em&gt; so I&amp;rsquo;m not going to be a hater.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.reddit.com/r/3Dprinting/comments/1r3ngj0/made_a_print_in_place_box_so_i_can_easily_hand/"&gt;Made a print in place box so I can easily hand out printed bees🐝&lt;/a&gt;. &amp;ldquo;Im quite content with the result, the bees fit snugly and the box opens and closes nicely&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://moreisdifferent.blog/p/yeast-based-vaccines-are-a-big-deal"&gt;Yeast-based vaccines are a big deal for biosecurity&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;There isn’t a lot of reliable information out there about how to buy a gas mask, especially for the specific purpose of living under state repression. But hopefully after reading &lt;a href="https://www.theverge.com/policy/868571/best-gas-masks"&gt;this guide&lt;/a&gt; you’ll feel equipped to make an educated decision.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;This &lt;a href="https://byte.tsundoku.io/"&gt;zoomable map shows every page of every issue of BYTE&lt;/a&gt; starting from the front cover of the first issue (top left) to the last page of the final edition (bottom right). The search bar runs RE2 regex over the full text of all 100k pages.&amp;rdquo; A lovely reminder that user-interfaces can be extremely fast &lt;em&gt;and&lt;/em&gt; information dense.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=LeUZmojH7p8"&gt;How Every* Milk Product Is Made&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://danfrank.ca/in-favour-of-trying-new-things/"&gt;In Favour of Trying New Things – Daniel Frank&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.lesswrong.com/posts/vzfz4AS6wbooaTeQk/staring-into-the-abyss-as-a-core-life-skill"&gt;Staring into the abyss as a core life skill&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <id>tag:kevinlynagh.com,2026-02-01:/newsletter/2026_02_01_vibe/</id>
    <title type="html">Easy VM sandboxes for LLM agents on MacOS, Miami &amp; Paris travel</title>
    <published>2026-02-01T00:00:00Z</published>
    <updated>2026-02-01T00:00:00Z</updated>
    <link rel="alternate" href="https://kevinlynagh.com/newsletter/2026_02_01_vibe/" type="text/html"/>
    <content type="html">&lt;p&gt;Hi friends,&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m traveling the next two weeks, drop me a line if you want to grab a coffee!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Miami Monday Feb 2 &amp;mdash; Tuesday Feb 10&lt;/li&gt;
&lt;li&gt;Paris Wednesday Feb 11 &amp;mdash; Sunday Feb 15&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id='llm-agent-virtual-machine-sandbox'&gt;&lt;a class='anchor' href='#llm-agent-virtual-machine-sandbox'&gt;LLM agent virtual machine sandbox&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The other day I asked &lt;a href="https://openai.com/codex/"&gt;OpenAI&amp;rsquo;s Codex agent&lt;/a&gt; to write me a lil&amp;rsquo; Rust program to use a bluetooth gamepad as a mouse, and I caught the agent reading files outside of the directory I started it in.
I found this quite surprising, since I assumed it&amp;rsquo;d be contained within the project folder.
(I was using the default settings, not the more permissive &lt;code&gt;--yolo&lt;/code&gt; mode.)&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t like the idea of an LLM agent rooting around my computer and uploading anything it finds to OpenAI, so I started shopping around for a &amp;ldquo;sandbox&amp;rdquo; &amp;mdash; something I could let an agent loose inside of while maintaining explicit control of what it sees.&lt;/p&gt;

&lt;p&gt;I searched around and was, unfortunately, unable to find any Mac solution that met my requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;be an actual VM, not a container thingy (containers are less secure, and on MacOS they require a Linux VM anyway)&lt;/li&gt;
&lt;li&gt;be easy to spin up/down quickly with no configuration ceremony&lt;/li&gt;
&lt;li&gt;not involve other people&amp;rsquo;s servers, subscriptions, etc., etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That&amp;rsquo;s fine &amp;mdash; I&amp;rsquo;ve been messing with virtual machines for 20 years now, surely I can throw something together in an hour or two!&lt;/p&gt;

&lt;p&gt;Well, uh, several busy weekends later, I&amp;rsquo;d like to present &lt;a href="https://github.com/lynaghk/vibe/"&gt;Vibe&lt;/a&gt;, an easy way to spin up virtual machines on ARM-based Macs.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m quite pleased with how it turned out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You type &lt;code&gt;vibe&lt;/code&gt; in a folder and in ~10 seconds are inside of a Linux virtual machine.&lt;/li&gt;
&lt;li&gt;The folder is automatically mounted within the VM, so you can monitor an agent&amp;rsquo;s work from the comfort of your regular Mac text editor, Git UI, etc.&lt;/li&gt;
&lt;li&gt;Common package caches (Cargo&amp;rsquo;s registry, Maven&amp;rsquo;s &lt;code&gt;~/.m2&lt;/code&gt;, mise-en-place) are also shared so the sandbox VM doesn&amp;rsquo;t need to re-download stuff.&lt;/li&gt;
&lt;li&gt;The binary is &amp;lt; 1 MB and has no dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Being able to run LLM agents as &lt;code&gt;root&lt;/code&gt; with &lt;code&gt;--yolo&lt;/code&gt; mode is a great experience.
It feels much more like managing an IC &amp;mdash; you provide the necessary context in a big prompt, tell them to install whatever tools they need, and then let them cook for while you go focus on something else.&lt;/p&gt;

&lt;p&gt;While the &lt;code&gt;vibe&lt;/code&gt; defaults are geared towards use as an LLM agent sandbox, you can customize everything with scripts and command line flags so you can use it for all sorts of other virtual machine purposes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lynaghk/vibe/"&gt;Check it out&lt;/a&gt; and let me know what you think!&lt;/p&gt;
&lt;h2 id='misc-stuff'&gt;&lt;a class='anchor' href='#misc-stuff'&gt;Misc. stuff&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I recently bought a &lt;a href="https://amzn.to/4a7cHSz"&gt;$150 GL-MT6000 router&lt;/a&gt; so I could make a separate &amp;ldquo;offline&amp;rdquo; network for stuff like my 3D-printer and Windows computer that I want to keep off the Internet.
The router is awesome! It comes with the open source OpenWRT firmware installed, which provides a fast web UI, simple text configs you can backup with &lt;code&gt;rsync&lt;/code&gt;, and lots of built-in functionality like AdGuard (blocks ads for every device on the network via DNS) and Wireguard/Tailscale (easy VPN so you can access your home network from anywhere).
Highly recommended.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Last newsletter I mentioned vibecoding a &lt;a href="https://github.com/lynaghk/copy-resized-from-mac-photos-app/"&gt;copy from mac photos app&lt;/a&gt; since I couldn&amp;rsquo;t get the functionality I needed from the otherwise great &lt;a href="https://github.com/FuzzyIdeas/Clop/"&gt;Clop&lt;/a&gt; Mac photo resizing utility.
Well it turns out the author subscribes to this newsletter, checked out my source code, and immediately added the feature.
If that isn&amp;rsquo;t enough of a coincidence, he also loved my &lt;a href="/papr/"&gt;powered air respirator&lt;/a&gt; project since he&amp;rsquo;s a woodworker too and has been &lt;a href="https://alinpanaitiu.com/blog/developing-hardwax-oil/"&gt;developing his own hardwax oils&lt;/a&gt; for the &lt;a href="https://gospodaria.com/collections/din-cafenea"&gt;turned coffee cups he sells&lt;/a&gt;.
I love the Internet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;In this post, we will explain why the “concurrency + floating point” hypothesis misses the mark, unmask the true culprit behind LLM inference nondeterminism, and explain how to defeat nondeterminism and obtain truly &lt;a href="https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/"&gt;reproducible results in LLM inference&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;In the past, almost everybody travelled on the left side of the road because that was the most sensible option for &lt;a href="https://www.worldstandards.eu/cars/driving-on-the-left/"&gt;feudal, violent societies&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://alexharri.com/blog/ascii-rendering"&gt;ASCII characters are not pixels: a deep dive into ASCII rendering&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=dUkLYOPRYH4"&gt;It sounds dumb but they really fixed a typo with a human leg&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=1Vjd6NmA9Hs"&gt;Every James Cameron Movie, Explained by James Cameron&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://applerankings.com/"&gt;Apple Rankings&lt;/a&gt;: The definitive list of good and bad apples.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://www.bloomberg.com/company/stories/how-bloomberg-terminal-ux-designers-conceal-complexity/"&gt;Bloomberg Terminal UX&lt;/a&gt; team is not messing around: &amp;ldquo;Making substantial changes, even good ones, will reliably annoy a percentage of customers, so Jeffery’s team plans redesigns with incremental updates that roll out over weeks or months. For example, when they wanted to flatten the gradient of an element, they wouldn’t do so all at once, instead changing it little by little each month.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TIL that the founder of Reuters started with &lt;a href="https://substack.com/@theterminalist/p-181940918"&gt;a carrier-pigeon line&lt;/a&gt; between Berlin and Paris before eventually laying their own transatlantic telegraph cable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <id>tag:kevinlynagh.com,2026-01-04:/newsletter/2026_01_tools/</id>
    <title type="html">Tools I loved in 2025</title>
    <published>2026-01-04T00:00:00Z</published>
    <updated>2026-01-04T00:00:00Z</updated>
    <link rel="alternate" href="https://kevinlynagh.com/newsletter/2026_01_tools/" type="text/html"/>
    <content type="html">&lt;p&gt;Hi friends!&lt;/p&gt;

&lt;p&gt;While answering &lt;a href="https://stephango.com/40-questions"&gt;40 questions to ask yourself every year&lt;/a&gt;, I realized I&amp;rsquo;d adopted a &lt;em&gt;bunch&lt;/em&gt; of new tools over 2025.
All of them have improved my life, so I want to share them with you so they might improve yours too =D&lt;/p&gt;

&lt;p&gt;A common theme is that all of my favorite tools promote a sort of coziness: They help you tailor the spaces where you spend your time to your exact needs and preferences.&lt;/p&gt;

&lt;p&gt;Removing little annoyances and adding personal touches &amp;mdash; whether to your text editor or your kitchen &amp;mdash; not only improves your day-to-day mood, but cultivates a larger sense of security, ownership, and agency, all of which I find essential to doing great work. (And making great snacks.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="#physical"&gt;Physical&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="#workshop-space"&gt;Workshop space&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#led-lighting"&gt;LED lighting&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#euroboxes"&gt;Euroboxes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#ikea-skadis-coffee-smoothie-station"&gt;Ikea Skadis coffee/smoothie station&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#ikea-maximera-drawers"&gt;Ikea Maximera drawers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="#digital"&gt;Digital&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="#emacs-and-llms"&gt;Emacs and LLMs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#a-little-photos-app-exporter"&gt;A little Photos.app exporter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#uv-python-dependencies"&gt;UV (Python dependencies)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#mise-en-place-all-dependencies"&gt;Mise-en-place (all dependencies)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#atuin-shell-history"&gt;Atuin (shell history)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#youtube-premium"&gt;YouTube Premium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#flowstorm-clojure-debugger"&gt;FlowStorm (Clojure debugger)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#whispertron-transcription"&gt;Whispertron (transcription)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="#misc-stuff"&gt;Misc. stuff&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;
&lt;h2 id='physical'&gt;&lt;a class='anchor' href='#physical'&gt;Physical&lt;/a&gt;&lt;/h2&gt;&lt;h3 id='workshop-space'&gt;&lt;a class='anchor' href='#workshop-space'&gt;Workshop space&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Last summer we moved to a ground-level apartment, giving me (for the first time in my life) my very own little workshop space:&lt;/p&gt;

&lt;p&gt;&lt;img src="shed.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re just renting the apartment, so building a larger shed isn&amp;rsquo;t an option, but it turns out that one can get quite a lot done with floor area barely larger than a sheet of plywood.&lt;/p&gt;

&lt;p&gt;I designed a &lt;a href="https://www.youtube.com/watch?v=KnNi6Tpp-ac"&gt;Paulk-style&lt;/a&gt; workbench top, cut it out on my friend&amp;rsquo;s CNC, and mounted it all on &lt;a href="https://www.instructables.com/How-to-build-a-sturdy-workbench-inexpensively/"&gt;screwed-together 2x4 legs&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="workshop_2025.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;So far I&amp;rsquo;ve mostly worked with cheap plywood from Hornbach, using the following tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/4poWo9E"&gt;Makita track saw&lt;/a&gt; for both rough and precision cuts. There&amp;rsquo;s a handy depth stop that makes it easy to do a shallow scoring cut before making a full cut, which reduces tearing out the thin veneer.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/49CAV8j"&gt;Fein wet/dry vac&lt;/a&gt; to collect dust/chips. This includes an electrical outlet you can plug tools in to so the vacuum automatically turns on when the tool is drawing power, which is great.&lt;/li&gt;
&lt;li&gt;My &lt;a href="/papr/"&gt;DIY powered air respirator&lt;/a&gt; built around a 3M Versaflo helmet has been working great &amp;mdash; it&amp;rsquo;s &lt;em&gt;so&lt;/em&gt; much more comfortable than fiddling with separate respirators and eye + ear protection. 
Since it takes 15 seconds to take on/off, I&amp;rsquo;m pretty much always wearing it when I&amp;rsquo;m doing anything in the shop.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sabre300.recordpower.com/sabre-250/"&gt;Record Power Sabre 250&lt;/a&gt; desktop bandsaw for quick cross cuts. The accuracy isn&amp;rsquo;t great, but I haven&amp;rsquo;t tried replacing the blade or tuning it much yet.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/4qGQykZ"&gt;Bosch 12V palm edge router&lt;/a&gt; extremely fun to use for rounding over and chamfering edges:
&lt;img src="/newsletter/2025_10_bed/workbench.jpg" alt=""&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3YiLEhU"&gt;Bosch 12V drill/driver&lt;/a&gt; is lightweight and compact, and comes with a handy right-angle attachment that I&amp;rsquo;ve actually used:
&lt;img src="driver.jpg" alt=""&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.nl/-/en/Bosch-Bench-Drill-drilling-diameter/dp/B005OQEK9W/"&gt;Bosch PBD 40&lt;/a&gt; - a drill press with digital speed control and zeroable digital depth gauge with 0.1mm precision. At $250, the 0.5mm play in the chuck is forgivable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The workbench has MFT-style 20mm &amp;ldquo;dog holes&amp;rdquo; on a 96mm grid, which allows for all sorts of useful accessories.&lt;/p&gt;

&lt;p&gt;For example: I purchased Hooked on Wood&amp;rsquo;s &lt;a href="https://www.youtube.com/watch?v=UM-4rPx16Wg"&gt;bench dog rail hinges&lt;/a&gt;, which makes it easy to flip the track up/down to slide wood underneath to make cross cuts:&lt;/p&gt;

&lt;p&gt;&lt;img src="crosscut.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.banggood.com/ENJOYWOOD-Aluminum-Alloy-Woodworking-MFT-Table-Hold-Down-Clamp-Woodworking-Desktop-Presser-Dare-for-Quick-Manual-Pressing-Plate-Woodworking-Machinery-Accessories-DIY-Clamps-p-1880707.html?cur_warehouse=CZ&amp;ID=62901206317948"&gt;$10 dog hole clamp&lt;/a&gt; on the right holds a stop block, which allows me to make repeated cuts.&lt;/p&gt;

&lt;p&gt;Since the dog holes were cut with a CNC and the rail is straight, square cuts can be made by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;making a known straight cut with the track saw on its track (whether on the workbench or outside on sawhorses)&lt;/li&gt;
&lt;li&gt;pushing this reference edge up against the two bench dogs on the top&lt;/li&gt;
&lt;li&gt;cutting along the track&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See &lt;a href="https://www.youtube.com/watch?v=X0r_rkXtSrw"&gt;Bent&amp;rsquo;s Woodworking&lt;/a&gt; for more detail on this process.&lt;/p&gt;

&lt;p&gt;While I wish I had space for a full size sliding table saw and/or CNC, this workbench and track saw seems like a decent backyard shed solution.&lt;/p&gt;
&lt;h3 id='led-lighting'&gt;&lt;a class='anchor' href='#led-lighting'&gt;LED lighting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Last winter I decided to fight the gloomy Dutch weather by buying a bunch of high-CRI LEDs to flood my desk with artificial daylight:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://kevinlynagh.com/newsletter/2025_03_cad/lit_desk.jpeg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://kevinlynagh.com/newsletter/2025_03_cad/#office-bright-light"&gt;build log&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;This lighting has worked out swimmingly &amp;mdash; it helps me wake up in the morning and makes the whole space feel nice even on the grayest rainy day.&lt;/p&gt;

&lt;p&gt;After sundown, my computer switches to &amp;ldquo;dark mode&amp;rdquo; colors and I switch the room to cozier warm-white LEDs.&lt;/p&gt;

&lt;p&gt;I had about 8 meters of LED strip leftover, which I used with &lt;a href="https://www.amazon.nl/-/en/dp/B07KZZVYCN"&gt;LED diffuser profiles&lt;/a&gt; to illuminate my workshop.&lt;/p&gt;
&lt;h3 id='euroboxes'&gt;&lt;a class='anchor' href='#euroboxes'&gt;Euroboxes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When we moved into our new (completely unfurnished) apartment over the summer, I was adamant I&amp;rsquo;d build all of the furniture we needed.
However, sightly storage solutions have taken longer than anticipated, so to eliminate the immediate clutter I purchased a bunch of &lt;a href="https://www.emtrade.nl/60x40x75-kunststof-bak-grijs-pp-gesloten-gebruikt.html?id=266599261"&gt;600x400x75mm euroboxes&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="euroboxes.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;At $4/each (used), they&amp;rsquo;re an absolute bargain.&lt;/p&gt;

&lt;p&gt;Since they&amp;rsquo;re plastic, they slide great on waxed wood rails and make perfect lil&amp;rsquo; utility drawers.
The constraint of needing to use fixed size drawers makes it easier for me to design the rest of a furniture piece around them.&lt;/p&gt;

&lt;p&gt;For example, just take a brad nailer to the limitless amounts of discarded particle board available on the streets of Amsterdam, and &lt;em&gt;boom&lt;/em&gt;, one-day-build 3d-printer cart in the meter closet:&lt;/p&gt;

&lt;p&gt;&lt;img src="3d_printer_stand.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;Or, throw some drawers in the hidden side of these living room plywood coffee table / bench / scooters:&lt;/p&gt;

&lt;p&gt;&lt;img src="cart.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;Now we have a tidy place to hide the TV remote and wireless keyboard/mouse, coffee table books, store extra blankets, etc.&lt;/p&gt;
&lt;h3 id='ikea-skadis-coffee-smoothie-station'&gt;&lt;a class='anchor' href='#ikea-skadis-coffee-smoothie-station'&gt;Ikea Skadis coffee/smoothie station&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our kitchen only has 1.6 m&lt;sup&gt;2&lt;/sup&gt; (17 ft&lt;sup&gt;2&lt;/sup&gt;) of counter space, so we mounted two Ikea Skadis pegboards to the side of our fridge to make a coffee / smoothie station:&lt;/p&gt;

&lt;p&gt;&lt;img src="coffee_station.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;The clear Ikea containers are great for nuts and coffee since you can grab them with one hand and drop &amp;lsquo;em in the blender or grinder.&lt;/p&gt;

&lt;p&gt;I designed and 3d-printed custom mounts for my &lt;a href="https://amzn.to/49i4cUu"&gt;Clever Dripper&lt;/a&gt;, coffee grinder (&lt;a href="https://1zpresso.coffee/k/"&gt;1Zpresso k-series&lt;/a&gt;), little water spritzer, and bottles of &lt;a href="https://friedhats.com/"&gt;Friedhats beans&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since we can&amp;rsquo;t screw into the fridge, the panels are hanging from some 3d-printed hooks &lt;a href="https://amzn.to/4qcqaQc"&gt;command stripped&lt;/a&gt; on the top of the fridge cabinet.
Clear nano-tape keeps the Skadis boards from swinging.&lt;/p&gt;

&lt;p&gt;The cheap &lt;a href="https://amzn.to/45oXOto"&gt;Ninja cup blender&lt;/a&gt; is quite loud, so we leave a pair of &lt;a href="https://amzn.to/49DYcGY"&gt;Peltor X4&lt;/a&gt; ear defenders hanging next to it.&lt;/p&gt;
&lt;h3 id='ikea-maximera-drawers'&gt;&lt;a class='anchor' href='#ikea-maximera-drawers'&gt;Ikea Maximera drawers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As soon as we made the smoothie station we decided to replace the cabinet shelves underneath it with drawers.
(The only drawers that came with the kitchen were installed underneath the range, creating constant conflict between the cook and anyone needing silverware.)&lt;/p&gt;

&lt;p&gt;Decent soft-close undermount drawer slides from Blum/Hettich cost like $30 each, and for the same price &lt;a href="https://www.ikea.com/nl/en/p/maximera-drawer-low-white-70319354/"&gt;Ikea sells slides &lt;em&gt;with&lt;/em&gt; a drawer box&lt;/a&gt; attached.&lt;/p&gt;

&lt;p&gt;Since we&amp;rsquo;re renting and can&amp;rsquo;t make permanent changes to the kitchen, I built a carcass for the drawers &lt;em&gt;within&lt;/em&gt; the existing cabinet:&lt;/p&gt;

&lt;p&gt;&lt;img src="drawer_carcass.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;The particle board sides carry the weight of the drawers to the base of the existing cabinet, and they&amp;rsquo;re fixed to the walls with nano-tape rather than screws.&lt;/p&gt;

&lt;p&gt;Nicki 3d-printed cute pulls and we threw those onto temporary fronts made of leftover MDF.
As you can see from the hardware poking through, these 8mm fronts are a bit too thin, so I plan to replace them with thicker MDF, probably sculpted with a goofy pattern in the style of &lt;a href="https://arnohoogland.com/projects/deus-ex-machina-exhibition"&gt;Arno Hoogland&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Having drawers is awesome:&lt;/p&gt;

&lt;p&gt;&lt;img src="drawers.jpg" alt=""&gt;&lt;/p&gt;

&lt;p&gt;We bought a bunch of extra cups for the Ninja blender and keep them pre-filled with creatine and protein powder.
The bottom drawer holds the dozen varieties of peanut butter remaining from the &lt;a href="https://gwern.net/socks"&gt;Gwern-inspired&lt;/a&gt; tasting I held in November.
(The UK&amp;rsquo;s &lt;a href="https://www.pipandnut.com/"&gt;Pip &amp;amp; Nut&lt;/a&gt; peanut butters were the crowd favorites, by the way.)&lt;/p&gt;
&lt;h2 id='digital'&gt;&lt;a class='anchor' href='#digital'&gt;Digital&lt;/a&gt;&lt;/h2&gt;&lt;h3 id='emacs-and-llms'&gt;&lt;a class='anchor' href='#emacs-and-llms'&gt;Emacs and LLMs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve used Emacs for something like 15 years, but after the first year or so I deliberately avoided trying to customize it, as that felt like too much of a distraction from the more important yaks I was shaving through my 20&amp;rsquo;s and early 30&amp;rsquo;s.&lt;/p&gt;

&lt;p&gt;However, in early 2025 I decided to dive in, for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I ran across &lt;a href="https://www.youtube.com/watch?v=d3aaxOqwHhI"&gt;Prot&amp;rsquo;s video&lt;/a&gt; demonstrating a cohesive set of well-designed search and completion packages, which suggested to me that there were interesting ideas being developed in the &amp;ldquo;modern&amp;rdquo; Emacs community&lt;/li&gt;
&lt;li&gt;I discovered &lt;a href="https://github.com/karthink/gptel"&gt;gptel&lt;/a&gt;, which makes it extremely easy to query large language models within Emacs &amp;mdash; just highlight text, invoke gtpel, and the response is inserted right there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What&amp;rsquo;s special about Emacs compared to other text editors is that it&amp;rsquo;s &lt;em&gt;extremely&lt;/em&gt; easy to customize.
Rather than a &amp;ldquo;text editor&amp;rdquo;, Emacs is better thought of as an operating system and live programming environment which just so happens to have a lot of functions related to editing text.&lt;/p&gt;

&lt;p&gt;My day-to-day coding, writing, and thinking environment within Emacs has improved tremendously in 2025, as every time I&amp;rsquo;ve had any sort of customization or workflow-improvement idea, I&amp;rsquo;ve been able to try it out in just a minute or two by having an LLM generate the necessary Emacs Lisp code.&lt;/p&gt;

&lt;p&gt;My mentality changed to &amp;ldquo;yeah, I&amp;rsquo;m sure it&amp;rsquo;s possible but I don&amp;rsquo;t have time or interest to figure out how to do it with this archaic and quirky programming language&amp;rdquo; to &amp;ldquo;let me spend two minutes trying&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Turns out there&amp;rsquo;s a lot of little improvements that can be done by an LLM in few minutes. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Literally for this article, I asked the LLM to write a Ruby method for my static site generator to render a table of contents (which you can see above!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lots of places don&amp;rsquo;t support markdown natively, so I had an LLM write me an Emacs function to render selected markdown text to HTML on the pasteboard, which lets me write in Emacs and then just &lt;code&gt;⌘V&lt;/code&gt; in Gmail to get a nicely formatted message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When I write markdown and want to include an image, it&amp;rsquo;s annoying to have to copy/paste in the path to the image, so I had an LLM write me an autocomplete against all of the image files in the same directory as the markdown file.
I&amp;rsquo;ve been using this for pretty much every article/newsletter I write now, since they usually have images.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I keep a daily activity log as a simple EDN file with entries like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:start&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;inst&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;2025-12-28T12:00+01:00&amp;quot;&lt;/span&gt; &lt;span class="ss"&gt;:tags&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;lunch&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;nicki&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="ss"&gt;:duration&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:start&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;inst&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;2025-12-28T09:00+01:00&amp;quot;&lt;/span&gt; &lt;span class="ss"&gt;:tags&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;paneltron&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;computering&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="ss"&gt;:duration&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
 &lt;span class="ss"&gt;:description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;rough out add-part workflow.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:start&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;inst&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;2025-12-28T08:20+01:00&amp;quot;&lt;/span&gt; &lt;span class="ss"&gt;:tags&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wakeup&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Everything&amp;rsquo;s rounded to the half-hour.)&lt;/p&gt;

&lt;p&gt;I started this when I was billing by the hour (a decade ago), and have kept it up because it&amp;rsquo;s handy to have a lightweight, low-friction record of what I&amp;rsquo;ve been up to.
I used to do occasional analysis manually via a REPL, but couldn&amp;rsquo;t sleep one night so I spent 30 minutes having an LLM throw together a visual summary which I can invoke for whatever week is under my cursor.
It looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Week: 2025-12-22 to 2025-12-28

Locations:
  Amsterdam - Friday 2025-12-19T13:30+01:00

computering       16.5h ##################
box-carts         14.5h ###############
woodworking       13.0h ##############
llms               8.0h ########
dinner             7.0h #######
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and includes my most recent &lt;code&gt;:location&lt;/code&gt; (an attribute I started tagging entries with to help keep track of visa limitations while traveling).&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m extremely chuffed about having quick access to weekly summaries and suspect that tying that to my existing habit of recording entries will be a good intra-week feedback loop about whether I&amp;rsquo;m spending time in alignment with my priorities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Whenever I write an article or long message, before sending it I run it by an LLM with the following prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;my friend needs feedback on this article &amp;mdash; are there any typos, confusing sentences, or other things that could be improved? Be blunt and I&amp;rsquo;ll convey the feedback to my friend in a friendly way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This one doesn&amp;rsquo;t even involve any code, it&amp;rsquo;s just a habit that&amp;rsquo;s easy because it&amp;rsquo;s easy to call an LLM from within Emacs.
LLMs will note repeated words, incorrect homonyms, and awkward sentences that simple spell-checkers miss.
Here&amp;rsquo;s an example from this very article:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Double parenthesis: &lt;code&gt;[Paulk-style]((https://www.youtube.com/watch?v=KnNi6Tpp-ac))&lt;/code&gt; — remove one set&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Ikea Maximara drawers&amp;rdquo; in the heading, but the product is actually &amp;ldquo;Maximera&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http://localhost:9292/newsletter/2025_06_03_prototyping_a_language/&lt;/code&gt; — you&amp;rsquo;ve left a localhost URL in the FlowStorm section&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Emacs has a pretty smooth gradient between &amp;ldquo;adjust a keybinding&amp;rdquo;, to &amp;ldquo;quick helper function&amp;rdquo;, to a full on workflow.
Here&amp;rsquo;s an example from the latter end of that spectrum.&lt;/p&gt;

&lt;p&gt;I asked Claude Code to make some minor CSS modifications for a project, then got nerd-sniped trying to understand why it used a million tokens to explore my 4000-word codebase and edit a dozen lines:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Usage by model:
        claude-haiku:  8.6k input, 5.4k output, 434.2k cache read, 33.4k cache write ($0.1207)
       claude-sonnet:  1.0k input, 262 output, 0 cache read, 0 cache write ($0.0069)
     claude-opus-4-5:  214 input, 8.3k output, 842.5k cache read, 47.8k cache write ($0.93)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After a bit of digging, it seemed likely this is a combination of factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code&amp;rsquo;s &lt;a href="https://github.com/Piebald-AI/claude-code-system-prompts"&gt;system and tool prompts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Repeatedly invoking tools to grep around the directory and read files 200 lines at a time&lt;/li&gt;
&lt;li&gt;Absolute nonsense &amp;mdash; Mario Zechner has some &lt;a href="https://mariozechner.at/posts/2025-12-22-year-in-review-2025/#toc_5"&gt;great analysis&lt;/a&gt; on this (fun fact: &amp;ldquo;Claude Code uses Haiku to generate those little whimsical &amp;quot;please wait&amp;rdquo; messages. For every. token. you. input.&amp;ldquo;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For comparison, I invoked Opus 4.5 manually with all of my source code and asked what I needed to change, and it nailed the answer using only 5000 tokens (4500 input, 500 output).&lt;/p&gt;

&lt;p&gt;So I leaned into this and wrote my own lightweight, single-shot workflow in Emacs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I write something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;@rewrite

/path/to/file1
/path/to/file2

Please do X, Y, Z, thanks!
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and when I send it, some elisp code:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;adds the specified files to the context window&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sets the system prompt to be &amp;quot;please reply only with a lil&amp;rsquo; string replacement patch format that looks like &amp;hellip;&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sends the LLM response to a &lt;a href="https://babashka.org/"&gt;Babashka&lt;/a&gt; script which applies this patch, sandboxed to just the specified files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;rsquo;ve used it a handful of times so far and it works exactly the way I&amp;rsquo;d imagined &amp;mdash; it&amp;rsquo;s much faster than waiting for an &amp;ldquo;agent&amp;rdquo; to make a dozen tool calls and lets me take advantage of LLMs for tedious work while remaining in the loop.&lt;/p&gt;

&lt;p&gt;(Admittedly, this one took a few hours rather than a few minutes, but it was well worth it in terms of getting some hands-on experience building a structured LLM-based workflow.)&lt;/p&gt;
&lt;h3 id='a-little-photos-app-exporter'&gt;&lt;a class='anchor' href='#a-little-photos-app-exporter'&gt;A little Photos.app exporter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you copy images out of Photos.app, it only puts a 1024 pixel wide &amp;ldquo;preview image&amp;rdquo; on the pasteboard.
This loses too much detail.&lt;/p&gt;

&lt;p&gt;The built-in &amp;ldquo;export&amp;rdquo; workflow is tedious to use and doesn&amp;rsquo;t actually compress well, so you have to do another pass through &lt;a href="https://squoosh.app/"&gt;Squoosh&lt;/a&gt; or &lt;a href="https://imageoptim.com/mac"&gt;ImageOptim&lt;/a&gt; anyway.
Of course, you&amp;rsquo;ll want to resize before you do that, maybe in Preview?&lt;/p&gt;

&lt;p&gt;I noticed how annoyed I was trying to add photos to my articles, so I vibe-coded &lt;a href="https://github.com/lynaghk/copy-resized-from-mac-photos-app"&gt;a little Photos.app exporter&lt;/a&gt; that behaves exactly like how I want.&lt;/p&gt;
&lt;h3 id='uv-python-dependencies'&gt;&lt;a class='anchor' href='#uv-python-dependencies'&gt;UV (Python dependencies)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I haven&amp;rsquo;t done much Python in my career, but it&amp;rsquo;s a popular language that I&amp;rsquo;d occasionally need to tap into to use some specific library (e.g., OpenCV, NumPy, JAX) or run the code behind some interesting research paper.&lt;/p&gt;

&lt;p&gt;The package management has always been (from my perspective of a casual outsider) an absolute mess.
Yes, with lots of good reasons related to packaging native code across different operating systems and architectures, etc. etc. etc.&lt;/p&gt;

&lt;p&gt;Whatever, if &lt;code&gt;pip install&lt;/code&gt; failed to build my eggs or wheels or whatever, I&amp;rsquo;d usually just give up.&lt;/p&gt;

&lt;p&gt;As for reproducibility and pinning to exact versions&amp;hellip;&lt;code&gt;¯\_(ツ)_/¯&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Maybe if I do nothing the problem will fix itself&amp;rdquo; isn&amp;rsquo;t a great problem solving strategy, but it definitely worked out for me for understanding Python dependency managers: I came across &lt;a href="https://docs.astral.sh/uv/"&gt;UV&lt;/a&gt; in late 2024 and it&amp;hellip;just works?
It&amp;rsquo;s also fast!&lt;/p&gt;

&lt;p&gt;I can now finally create a Python project, specify some dependencies, and automatically get a lockfile ensuring it&amp;rsquo;ll will work just fine on my other computer, 6 months from now!&lt;/p&gt;

&lt;p&gt;This problem has been a thorn in the side of not just software developers, but also scientific researchers for &lt;em&gt;decades&lt;/em&gt;.
The folks who&amp;rsquo;ve finally resolved it deserve, like, the Nobel Peace prize.&lt;/p&gt;
&lt;h3 id='mise-en-place-all-dependencies'&gt;&lt;a class='anchor' href='#mise-en-place-all-dependencies'&gt;Mise-en-place (all dependencies)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This past year I&amp;rsquo;ve also been loving &lt;a href="https://mise.jdx.dev/"&gt;mise-en-place&lt;/a&gt;.
From their homepage:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;mise is a tool that manages installations of programming language runtimes and other tools for local development. For example, it can be used to manage multiple versions of Node.js, Python, Ruby, Go, etc. on the same machine.&lt;/p&gt;

&lt;p&gt;Once activated, mise can automatically switch between different versions of tools based on the directory you&amp;rsquo;re in. This means that if you have a project that requires Node.js 18 and another that requires Node.js 22, mise will automatically switch between them as you move between the two projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&amp;rsquo;ve used language-specific versions of this idea, and it&amp;rsquo;s been refreshing to throw all of those out in favor of a single uniform, fast solution.&lt;/p&gt;

&lt;p&gt;I have a user-wide &amp;ldquo;default&amp;rdquo; config, containing stuff like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;languages (a JVM, clojure, ruby)&lt;/li&gt;
&lt;li&gt;language servers (clojure-lsp, rust analyzer, etc.)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tummychow/git-absorb"&gt;git-absorb&lt;/a&gt; &amp;ldquo;git commit &amp;ndash;fixup, but automatic&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://difftastic.wilfred.me.uk/"&gt;Difftastic&lt;/a&gt; AST-aware diffing&lt;/li&gt;
&lt;li&gt;&lt;a href="https://numbat.dev/"&gt;Numbat&lt;/a&gt;, an awesome unit-aware scientific calculator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and on specific projects I specify the same and additional tools, so that collaborators can have a &amp;ldquo;single install&amp;rdquo; that guarantees we&amp;rsquo;re all on the same versions of everything.&lt;/p&gt;

&lt;p&gt;Sure something like &lt;a href="https://en.wikipedia.org/wiki/Nix_(package_manager)"&gt;Nix&lt;/a&gt; with hermetically sealed, content addressed, etc., etc. is better in theory, but the UX and conceptual model is a mess.&lt;/p&gt;

&lt;p&gt;Mise feels like a strong, relatively simple local optimum: You specify what you want through a simple hierarchy of configs, mise generates lockfiles, downloads the requested dependencies, and puts them on the &lt;code&gt;$PATH&lt;/code&gt; based on where you are.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve been using it for a year and haven&amp;rsquo;t had to learn anything beyond what I did in the first 15 minutes. It works.&lt;/p&gt;
&lt;h3 id='atuin-shell-history'&gt;&lt;a class='anchor' href='#atuin-shell-history'&gt;Atuin (shell history)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://atuin.sh/#cli-section"&gt;Atuin&lt;/a&gt; records all of your shell commands, (optionally) syncs them across multiple computers, and makes it easy to recall commands with a fuzzy finder.
It&amp;rsquo;s all self-hostable and is distributed as a single binary.&lt;/p&gt;

&lt;p&gt;I find the shell history extremely useful, both for remembering infrequently used commands, as well as for simply avoiding typing out tediously long ones with many flags.
Having a proper fuzzy search that shows a dozens of results (rather than just one at a time) makes it straightforward to use.&lt;/p&gt;

&lt;p&gt;Before this I wouldn&amp;rsquo;t have thought twice about my shell command history, and now it&amp;rsquo;s something I deliberately back up because it&amp;rsquo;s so useful.&lt;/p&gt;
&lt;h3 id='youtube-premium'&gt;&lt;a class='anchor' href='#youtube-premium'&gt;YouTube Premium&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At some point in 2025 the ad-blocker I was using stopped working on YouTube and I started seeing either pauses or (uggghhh) commercials (in Dutch, which Google must think I understand, despite 15 years of English GMail, not to mention my &lt;code&gt;Accept-Language&lt;/code&gt; header).&lt;/p&gt;

&lt;p&gt;Given that YouTube is a Wonder of the World and a $20/month leaves me with a consumer surplus in the neighborhood of $10&lt;sup&gt;4&lt;/sup&gt;&amp;ndash;10&lt;sup&gt;5&lt;/sup&gt;, I decided to subscribe to YouTube Premium.&lt;/p&gt;

&lt;p&gt;Honestly I just wanted the ads to stop, but it&amp;rsquo;s even better &amp;mdash; I can conveniently download videos to my phone, which means I can watch interesting videos while riding on the stationary exercise bike in the park near my house.&lt;/p&gt;

&lt;p&gt;It also comes with YouTube Music, which immediately played me a late 00&amp;rsquo;s indie rock playlist that brought me back to college.&lt;/p&gt;

&lt;p&gt;100% worth it.&lt;/p&gt;
&lt;h3 id='flowstorm-clojure-debugger'&gt;&lt;a class='anchor' href='#flowstorm-clojure-debugger'&gt;FlowStorm (Clojure debugger)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I don&amp;rsquo;t normally use debuggers, especially since in Clojure it&amp;rsquo;s usually straightforward to pretty-print the entire application state.&lt;/p&gt;

&lt;p&gt;However, this usual approach failed me when I was &lt;a href="/newsletter/2025_06_03_prototyping_a_language/"&gt;building an interpreter&lt;/a&gt; for some CAD programming language experiments &amp;mdash; each AST node holds a reference to its environment (a huge map), and simply printing a tree yields megabytes of text.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.flow-storm.org/"&gt;FlowStorm&lt;/a&gt; takes advantage of the fact that idiomatic Clojure uses immutable data structures &amp;mdash; the debugger simply holds a reference to every value generated during a computation, so that you can analyze them later.&lt;/p&gt;

&lt;p&gt;There are facilites to search all of the recorded values.
So if you a see a string &amp;ldquo;foo&amp;rdquo; on your rendered webpage or whatever, you can easily answer questions like &amp;ldquo;where is the first callstack where the string &amp;lsquo;foo&amp;rsquo; shows up?&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;All of the recorded data is available programmatically too.
I used this infrastructure to make a &lt;a href="https://kevinlynagh.com/misc/2025_12_08_2dtron_demo.mp4"&gt;live visualization of a 2D graphics program&lt;/a&gt; where as you move your cursor around the program source code, you see the closest graphical entity rendered automatically.&lt;/p&gt;

&lt;p&gt;(&amp;ldquo;A debounced callback triggered by cursor movement which executes Clojure code and highlights text according to the return value&amp;rdquo; is another example of an Emacs customization I never would have attempted prior to LLMs.)&lt;/p&gt;
&lt;h3 id='whispertron-transcription'&gt;&lt;a class='anchor' href='#whispertron-transcription'&gt;Whispertron (transcription)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I vibe-coded &lt;a href="/newsletter/2024_10_transcription_app_art_wall/"&gt;my own lil&amp;rsquo; voice transcription app&lt;/a&gt; back in October 2024, but I&amp;rsquo;m including it in this list because using it has become second-nature to me in 2025.&lt;/p&gt;

&lt;p&gt;Before I had reliable transcription at my fingertips, I never felt hindered by my typing speed (~125 words per minute).
However, now that I have it, I find that I&amp;rsquo;m expressing &lt;em&gt;much&lt;/em&gt; more when I&amp;rsquo;m dictating compared to typing.&lt;/p&gt;

&lt;p&gt;It reminds me of the difference between responding to an email on an iPhone versus using a computer with a large monitor and full keyboard.
I find myself providing much more context and otherwise elaborating my thoughts in more detail.
It&amp;rsquo;s just &lt;em&gt;easier&lt;/em&gt; to speak out loud than type out the same information.&lt;/p&gt;

&lt;p&gt;This yields much better results when prompting LLMs: typing, I&amp;rsquo;ll say &amp;ldquo;do X&amp;rdquo;; speaking, I&amp;rsquo;ll say &amp;ldquo;do X, maybe try A, B, C, remember about Y and Z constraints&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;It also yields better relationships: When emailing and texting friends, I&amp;rsquo;ll dictate (and then clean up / format) much more detailed, longer responses than what I&amp;rsquo;d type.&lt;/p&gt;
&lt;h2 id='misc-stuff'&gt;&lt;a class='anchor' href='#misc-stuff'&gt;Misc. stuff&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I&amp;rsquo;ve been experimenting with making keyboard-driven, data-dense interfaces on the web.
So far I&amp;rsquo;ve been using the same DataScript + Rum + Elm-style architecture that I&amp;rsquo;ve been using since &lt;a href="http://subformapp.com/"&gt;Subform&lt;/a&gt; in 2016, but I&amp;rsquo;m looking at updating to &lt;a href="https://replicant.fun/"&gt;Replicant&lt;/a&gt; and Nexus, which look pretty solid.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One piece I &lt;a href="/newsletter/2023_11_programming_languages/"&gt;still&lt;/a&gt; find myself missing in Clojure is modeling my application state with algebraic data types and having my tooling remind me to handle all of the possible cases. I&amp;rsquo;m not thrilled about writing UI in Rust, but nor does it seem like a good idea to pick up and try to master a new language (F#, Gleam, TypeScript, &amp;hellip;Elm?).
I&amp;rsquo;ll be investigating tools and patterns to try and get some of the &amp;ldquo;statically typed&amp;rdquo; developer experience in Clojure &amp;mdash; if you have any suggestions, I&amp;rsquo;d love to hear &amp;lsquo;em!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=DydIhwLrbMk"&gt;Portals must bend gravity, actually&lt;/a&gt;. Video games that don&amp;rsquo;t respect conservation of energy &lt;em&gt;really&lt;/em&gt; bothers some folks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;So yes, &lt;a href="https://www.jenn.site/why-canada-really-lost-its-measles-elimination-status/"&gt;Canada lost its measles elimination status&lt;/a&gt; today. But we can get it back in a year and a bit, if we&amp;rsquo;re serious. And if we&amp;rsquo;re serious about eliminating measles again, we need to focus more on investing in healthcare workers who speak the language of and can build relationships in communities, and less on implying that certain populations are just inherently unreachable, which just seems like a fundamentally anti-helpful thing to do.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=sceGtaNHxcM"&gt;One year of building my own IDE in clojure&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=oYU2hAbx_Fc"&gt;Who watches the Waymos?&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://mariozechner.at/posts/2025-11-30-pi-coding-agent/"&gt;What I learned building an opinionated and minimal coding agent&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;We’re not sure why. Going into the study, we assumed that all three techniques created the correct muscular configuration for an expression of happiness. But we found some evidence that the pen-in-mouth condition may not be actually creating &lt;a href="https://news.stanford.edu/stories/2022/10/posing-smiles-can-brighten-mood"&gt;an expression that closely resembles smiling&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.smokingonabike.com/2025/12/31/web-browsers-have-stopped-blocking-pop-ups/"&gt;Web browsers have stopped blocking pop-ups&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=_3qzyAHMoUU"&gt;Obra Dinn&amp;rsquo;s &amp;ldquo;pixel art&amp;rdquo; is actually genius&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=mFBmoCv5EcQ"&gt;Game Architectures with Alex Evans and Anton Mikhailov&lt;/a&gt; - The folks behind the world-building videogame &lt;em&gt;Dreams&lt;/em&gt; discuss implementing a purely deterministic game engine with functional updates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://eyeondesign.aiga.org/for-decades-cartographers-have-been-hiding-covert-illustrations-inside-of-switzerlands-official-maps/"&gt;For Decades, Cartographers Have Been Hiding Covert Illustrations Inside of Switzerland’s Official Maps&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.mikeayles.com/#tokn"&gt;TOKN: Token-Optimised KiCad Notation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <id>tag:kevinlynagh.com,2025-11-16:/newsletter/2025_11_shoe_tower/</id>
    <title type="html">Pindakaas party, plywood problems, and CNC daydreams</title>
    <published>2025-11-16T00:00:00Z</published>
    <updated>2025-11-16T00:00:00Z</updated>
    <link rel="alternate" href="https://kevinlynagh.com/newsletter/2025_11_shoe_tower/" type="text/html"/>
    <content type="html">&lt;h2 id='peanut-butter-tasting'&gt;&lt;a class='anchor' href='#peanut-butter-tasting'&gt;Peanut butter tasting (!!!)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recently re-read Gwern &lt;a href="https://gwern.net/socks"&gt;On Having Enough Socks&lt;/a&gt; and, uh, now I&amp;rsquo;m hosting a blind-tasting of a dozen peanut butters this Saturday, November 22 in Amsterdam.
If you&amp;rsquo;re in town, email me for the event details.
Together we will find the best 100% pindakaas met stukjes.&lt;/p&gt;
&lt;h2 id='a-shoe-tower'&gt;&lt;a class='anchor' href='#a-shoe-tower'&gt;A shoe tower&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The weather has turned chilly, and my girlfriend is &lt;em&gt;highly&lt;/em&gt; encouraging me to build some bedroom storage so our coats and sweaters are more accessible.&lt;/p&gt;

&lt;p&gt;Since making a standard box wardrobe out of plywood would be more expensive and time consuming yet aesthetically indistinguishable from Ikea, I decided to explore a lightweight frame using the hardwood dowels left over from my &lt;a href="/newsletter/2024_03_desk/"&gt;floating castle desk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In particular, I wanted to cut a groove in the dowels to hold (and hide) the raw edge of thin plywood shelves.&lt;/p&gt;

&lt;p&gt;I 3D-printed a custom shoe for my lil&amp;rsquo; trim router:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/router1.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;but this yielded poor results, so I ended up buying a full-sized plunge router.&lt;/p&gt;

&lt;p&gt;As it turns out, it takes a lot to hold round wood down securely to a table and route a groove exactly down the center.
I eventually got there with enough scrap material, clamps, and track saw track as straight edge:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/router2.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;Since I was using decorative pan head screws, I needed both through holes (for the screw shafts) and counterbores (for the shiny heads) along the dowels.
Free-handing with a drill worked about as well as you might expect &amp;mdash; turns out it&amp;rsquo;s &lt;em&gt;very&lt;/em&gt; obvious when a 15mm diameter counterbore isn&amp;rsquo;t exactly centered on a 20mm diameter dowel &amp;mdash; so I ended up buying a benchtop drill press:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/drill.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://www.amazon.nl/-/en/Bosch-Bench-Drill-drilling-diameter/dp/B005OQEK9W/"&gt;Bosch PBD 40&lt;/a&gt; has some awesome features like electronic speed control and digital depth readout.
Unfortunately, it also came with noticeable wiggle in the chuck and about 1mm deviation between the base plate&amp;rsquo;s v-groove and the drill center, both of which make it impossible to throw material down and get a repeatable hole location &amp;mdash; you have to carefully line everything up first.&lt;/p&gt;

&lt;p&gt;As far as I can tell (please let me know if I&amp;rsquo;m wrong!) there&amp;rsquo;s not really anything better on the market until you&amp;rsquo;re willing to spend for the &lt;a href="https://www.teknatool.com/products/drill-presses/benchtop-83700/"&gt;$1,400 Nova Viking&lt;/a&gt; benchtop drill press.&lt;/p&gt;

&lt;p&gt;After much drilling, I decided there was absolutely no way I was going to enjoy building a shoe tower using dowels (much less an entire bedroom storage system), so I demoted this prototype down to &amp;ldquo;plant stand&amp;rdquo;, which ended up turning out OK:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/plant_stand.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;(Just ignore all those extra holes.)&lt;/p&gt;

&lt;p&gt;I used brass tube to hide the screw threads.
Originally I thought I&amp;rsquo;d be able to easily cut brass tube with a hacksaw &amp;mdash; turns out absolutely not; brass is way too gummy and it&amp;rsquo;s impossible (for me, anyway) to maintain a consistent cut line by hand.
Luckily, I found one of these $10 things which, pleasingly, is extremely good at its one job:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/tube_cutter.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;(Notice the the right side piece was crushed in a drill chuck &lt;em&gt;and&lt;/em&gt; has an all-over-the-place failed cut from me earlier attempting to cut it by spinning it against a clamped-down hacksaw.)&lt;/p&gt;

&lt;p&gt;For my second shoe tower attempt, I wanted a lightweight plywood frame combined with fabric &amp;mdash; something in the direction of &lt;a href="https://www.miekemeijer.com/airframe-01"&gt;Mieke Meijer&amp;rsquo;s Airframe cabinet&lt;/a&gt; (which looks cool as hell).&lt;/p&gt;

&lt;p&gt;That build went much more smoothly, and the final product turned out better than I expected:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/shoe_tower.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;The only hiccup during the build was discovering that my dowel jig won&amp;rsquo;t work with material thinner than 15mm (my plywood was 12mm).
I made a sort of jig/guide using my new drill press and a bit of scrap wood, but the final joints still turned out a bit wonky.&lt;/p&gt;

&lt;p&gt;This is a typical woodworking experience for me &amp;mdash; a seemingly simple task like &amp;ldquo;drill holes centered in a plywood edge&amp;rdquo; takes two hours longer than expected, and even then doesn&amp;rsquo;t come out quite right. &lt;code&gt;¯\_(ツ)_/¯&lt;/code&gt;&lt;/p&gt;
&lt;h2 id='have-you-tried-rubbing-some-computer-on-it'&gt;&lt;a class='anchor' href='#have-you-tried-rubbing-some-computer-on-it'&gt;Have you tried rubbing some computer on it?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Back when I had a &lt;a href="/cnc-enclosure/"&gt;CNC router in my closet&lt;/a&gt;, I used to think it&amp;rsquo;d be so much faster to work in a more traditional workshop with proper saws and drill presses and stuff.&lt;/p&gt;

&lt;p&gt;But now that I&amp;rsquo;m frustrated in my back garden shed, discovering that I&amp;rsquo;m missing the appropriate drill size / pattern bit / alignment jig and spending hours carefully drilling not-quite-centered holes, I&amp;rsquo;ve started daydreaming that, surely, a &amp;ldquo;conversational&amp;rdquo; CNC router workflow could be better: clamp stuff down to the machine bed, get a high resolution / magnified image of the work, and specify exactly where and what to cut by pointing at stuff in the computer.&lt;/p&gt;

&lt;p&gt;Ideally you&amp;rsquo;d get an orthographic image &amp;mdash; a top-down projection without any perspective distortion.&lt;/p&gt;

&lt;p&gt;Since I&amp;rsquo;m not about to shell out a few grand for a &lt;a href="https://en.wikipedia.org/wiki/Telecentric_lens"&gt;telecentric lens&lt;/a&gt;, I started falling down a rabbit hole of building my own camera by using the machine gantry to move a large CCD line-sensor across the bed.&lt;/p&gt;

&lt;p&gt;The TCD1304, for example, has 3648 pixels over a 29mm sensor line, runs about $10 on AliExpress, and is used by solid looking &lt;a href="https://github.com/drmcnelson/Linear-CCD-with-LTSpice-KiCAD-Firmware-and-Python-Library"&gt;open-source hardware and firmware&lt;/a&gt; (they&amp;rsquo;re popular sensors for making your own spectrometer, apparently).&lt;/p&gt;

&lt;p&gt;However, I realized that I know basically nothing about optics.
Seeing the details of this &lt;a href="https://hackaday.io/project/202945-project-gigapixel-linear-ccd-camera"&gt;gigapixel camera from flatbed scanner CCD&lt;/a&gt; disabused me of the notion that I&amp;rsquo;d have a snowball&amp;rsquo;s chance in hell of making a usable camera.&lt;/p&gt;

&lt;p&gt;I spent some time with ChatGPT&amp;rsquo;s &lt;em&gt;Deep Research&lt;/em&gt; exploring other ideas, but it didn&amp;rsquo;t come up with much besides reminding me that I&amp;rsquo;ve been &lt;a href="/cncv/"&gt;spewing tokens on this bullshit&lt;/a&gt; for a while now:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/research.png"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;Good ol&amp;rsquo; YouTube came to the rescue, though &amp;mdash; &lt;a href="https://www.youtube.com/@PaperTools/videos"&gt;Paper Tools&lt;/a&gt; cleverly avoids the entire perspective distortion problem by only allowing you to pick coordinates from the center of the camera image.&lt;/p&gt;

&lt;p&gt;I.e., rather than giving you a static orthographic image that you then CAD/CAM on top of, their workflow requires that you literally drive your CNC machine around to the exact point locations every time you select one.&lt;/p&gt;

&lt;p&gt;Quite an obvious solution in hindsight, and I&amp;rsquo;m curious to watch how that project unfolds.&lt;/p&gt;
&lt;h2 id='next-drawers'&gt;&lt;a class='anchor' href='#next-drawers'&gt;Next: Drawers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After a week of daydreaming about an alternative, fluid conversational CAD/CAM interfaces for the CNC router currently across the Atlantic Ocean from me, I came back to my senses and decided to keep prototyping furniture ideas sans computer.&lt;/p&gt;

&lt;p&gt;I figured solid wood might be more satisfying than plywood.
Of course, I don&amp;rsquo;t have a jointer, planer, nor experience working with actual hardwoods, but I do have some leftover 2x softwood I can start with.&lt;/p&gt;

&lt;p&gt;My current idea is to lean heavily on bright colors &amp;mdash; paint, 3d-printed plastic, and paracord.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m experimenting with cross-bracing using the latter two materials:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_11_shoe_tower/cord.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;For the life of me I can&amp;rsquo;t find a stopper knot that I can slide or otherwise tie under tension &amp;mdash; if you have any ideas or suggestions of how to get a tidy looking knot that&amp;rsquo;ll slide to the left, I&amp;rsquo;d love to hear them!&lt;/p&gt;
&lt;h2 id='misc-stuff'&gt;&lt;a class='anchor' href='#misc-stuff'&gt;Misc. stuff&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;My &lt;a href="/papr/#2025-nov-3-update-dual-fan"&gt;powered air respirator now works great&lt;/a&gt;: I ended up going with a dual-fan design and dropped the belt clip in favor of an easier-to-don sling bag.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I love the engineering competence and details in this &lt;a href="https://media.defense.gov/2025/Sep/17/2003800984/-1/-1/0/CG-115_INTERVIEW-DEEP-SEA-EXPLORER_REDACTED.PDF"&gt;NTSB interview with a submersible expert&lt;/a&gt;. The names are all redacted, but you might be able to guess the interviewee from his first answer: &amp;ldquo;Well, I&amp;rsquo;m sure you&amp;rsquo;re familiar with my film &lt;em&gt;Titanic&lt;/em&gt;&amp;rdquo;. I also particularly liked one of the safety discussions: &amp;ldquo;I think the most dangerous part of our whole operation was these young software engineers puking over the railing in a high sea.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://acesounderglass.com/2025/10/13/the-biochemical-beauty-of-retatrutide-how-glp-1s-actually-work/"&gt;The Biochemical Beauty of Retatrutide: How GLP-1s Actually Work&lt;/a&gt;. I&amp;rsquo;ve never studied physiology, and this article was a perfect overview of one of the most exciting medical advances of the recent years. I was also delighted when the author connected biochemistry with familiar endurance running feelings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speaking of nicer visual / probing systems for CNCs, this now-on-Kickstarter &lt;a href="https://www.nestworks.ai/"&gt;Nestworks C500&lt;/a&gt; has a bunch of nice looking quality of life details. I swear it was just yesterday I dropped $10k for a Shopbot Desktop with a sketchy USB connection. I&amp;rsquo;m so lucky to have such deflationary hobbies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=HEtLee4IliA"&gt;Your cheap furniture has a secret&lt;/a&gt;. A history of rubberwood.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=tWYxrowovts"&gt;How Did The World Get So Ugly?&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=v8SLCwLzy2I"&gt;Smells Like Teen Spirit (Synth Pop 80s)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I&amp;rsquo;m renting a place with gas cooktop, but I wanted induction so I bought the &lt;a href="https://www.ikea.com/nl/en/p/tillreda-portable-induction-hob-1-zone-white-80590155/"&gt;€40 Ikea single-burner&lt;/a&gt; and am extremely happy with it. Normally not a fan of touch controls, but it has extremely responsive ones. The protocol between the display and induction coil has also been &lt;a href="https://hackaday.io/project/203350-diy-pwm-controlled-ikea-tillreda-induction-cooktop"&gt;reverse engineered&lt;/a&gt; in case you want to add your own control loop. (I don&amp;rsquo;t need another project, I don&amp;rsquo;t need another project..)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;They needed to connect the organ promptly to the patient manually, with a technique called anastomosis. The medical sutures of the time were too thick, and the needles too large, to avoid damaging delicate blood vessels. To overcome such challenges, the world needed &lt;a href="https://press.asimov.com/articles/liver"&gt;a skilled seamstress&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;ldquo;Complexity is free in 3d printing, the limit of design geometry is mostly how much time you’re willing to spend in CAD. I wanted to print &lt;a href="https://willmorrison.net/posts/marble-fountain/"&gt;the most complicated art piece I could think of&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I was curious how the support structures were generated, so I asked Claude to read the code and it gave me &lt;a href="https://gist.github.com/lynaghk/e3761bcdc65cb47823faa11d96c1ad67"&gt;a great explanation&lt;/a&gt; for $0.04. What a world!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.lesswrong.com/posts/gPPdYTwPkdvAEYyEK/fucking-goddamn-basics-of-rationalist-discourse"&gt;Fucking Goddamn Basics of Rationalist Discourse&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=nEt06LLQaBY"&gt;SpreadSheesh!&lt;/a&gt; by Dennis Heihoff - Clojure Electric-based spreadsheet with live code evaluation and custom UI rendering&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <id>tag:kevinlynagh.com,2025-10-11:/newsletter/2025_10_bed/</id>
    <title type="html">A constraint language, bedframe, and air handling trouble</title>
    <published>2025-10-11T00:00:00Z</published>
    <updated>2025-10-11T00:00:00Z</updated>
    <link rel="alternate" href="https://kevinlynagh.com/newsletter/2025_10_bed/" type="text/html"/>
    <content type="html">&lt;p&gt;Hi friends!&lt;/p&gt;

&lt;p&gt;I had an absolute blast in New York City visiting all of y&amp;#39;all who replied to my last email.
Shout out to those who offered to host me, even after I typo&amp;rsquo;d my dates and suggested I&amp;rsquo;d be in town for a month rather than a week &amp;mdash; true Internet friendship right there!&lt;/p&gt;

&lt;p&gt;NYC has a creative energy and depth that I haven&amp;rsquo;t felt elsewhere &amp;mdash; London and Taipei by comparison have much better transit infrastructure (and aren&amp;rsquo;t as deafeningly loud), but New York definitely feels to me more like the &amp;ldquo;capital of the world&amp;rdquo; with all the mixing of social/economic classes, variety of national backgrounds, and enormous variety of snacks.&lt;/p&gt;

&lt;p&gt;I also love how New Yorkers comment out loud and otherwise interact with strangers to navigate public situations together.&lt;/p&gt;
&lt;h2 id='a-simple-constraint-language'&gt;&lt;a class='anchor' href='#a-simple-constraint-language'&gt;A simple constraint language&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In between hanging with friends in New York, I found a few hours for programming and knocked out a new codeCAD prototype.
So far this one is more of a Clojure library rather than full interpreter/language.
The key idea is to lazily solve numeric variables only when the ground value is actually required (i.e., when calling OpenCascade C++ code that doesn&amp;rsquo;t know anything about constraints).&lt;/p&gt;

&lt;p&gt;This allows one to use numeric variables and constraints fluidly across functions, with parameters acting as &amp;ldquo;in/out&amp;rdquo; variables.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s an example (hypothetical syntax) showing how the relationship between a circle&amp;rsquo;s radius and diameter could be encapsulated within the circle function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(defn circle [center: Point
              radius: Length = 1
              diameter: Length = 2]

  (constraint (= radius (* 0.5 diameter)))

  ;; imagine some call here that actually draws the circle
  ;; and so requires radius and diameter to be solved...
)

some-point = [0, 0]

;; numeric variable, initial value of 5
dia = ?5

(circle some-point
        :radius     5
        :diameter dia)

;; now when you use the dia variable, it&amp;#39;s going to always be 10
;; This is forced by the circle fn constraint and radius argument
dia ;; =&amp;gt; 10
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;My hypothesis is that this might be very useful for all sorts of reusable geometric stuff.
We&amp;rsquo;ll see how that works out as I keep building it out and developing my own lil&amp;rsquo; OpenSCAD-like system.&lt;/p&gt;
&lt;h2 id='bed-completed'&gt;&lt;a class='anchor' href='#bed-completed'&gt;Bed completed&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Back in July we discussed &lt;a href="/newsletter/2025_07_flatpack/"&gt;flatpack bed ideas&lt;/a&gt;, and I&amp;rsquo;m happy to report that I&amp;rsquo;ve completed a first prototype:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_10_bed/bed.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;For the past few weeks it has successfully met the design objectives of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;lifting the mattress off the floor&lt;/li&gt;
&lt;li&gt;creating a ton space where we can hide boxes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I&amp;rsquo;m pretty chuffed with how it looks, too.
I wish I could take credit for the wild striping pattern, but that wasn&amp;rsquo;t my idea &amp;mdash; one sheet just arrived like that (apparently within spec for CP/CP birch plywood) and we decided to roll with it.&lt;/p&gt;

&lt;p&gt;The bed design is simple, with symmetric headboard/footboard panels joined to rails with M6 screws / threaded inserts and some metal dowels for additional shear support and to ease assembly:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_10_bed/pegbed.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;I designed for the 180x200 cm Ikea mattress we already had, and the frame is pretty much all Ikea internally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a pair of &lt;a href="https://www.ikea.com/nl/en/p/lonset-slatted-bed-base-s89481369/"&gt;Lonset&lt;/a&gt; slats&lt;/li&gt;
&lt;li&gt;resting on a &lt;a href="https://www.ikea.com/nl/en/p/skorva-midbeam-galvanised-90124534/"&gt;Skorva&lt;/a&gt; metal midbeam&lt;/li&gt;
&lt;li&gt;attached via metal plates that&amp;rsquo;re screwed into the headboard/footboard&lt;/li&gt;
&lt;li&gt;laterally braced with thin metal strips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_10_bed/bed_internals.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;The latter parts aren&amp;rsquo;t available for purchase, but Ikea offers spare parts &amp;mdash; and I can truthfully say that I&amp;rsquo;ve lost parts of the Malm bed I purchased in my 20&amp;rsquo;s.&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_10_bed/spare.png"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;Everything was cut out on my friend&amp;rsquo;s CNC:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_10_bed/bed_cnc.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;This took two days, as we spent most of the first day debugging why his CNC couldn&amp;rsquo;t cut reasonable circles.
This turned out to be backlash from a loose X-axis pinion/rack &amp;mdash; I&amp;rsquo;m now two-for-two diagnosing this exact problem on the CNC routers I&amp;rsquo;ve cajoled my way into operating here in Amsterdam.
Weird.&lt;/p&gt;

&lt;p&gt;The pieces were then cleaned up and the edges rounded over using Bosch&amp;rsquo;s &lt;a href="https://amzn.to/3L5Sx2t"&gt;adorable trim router&lt;/a&gt; (highly recommended) and the MFT/Paulk-style workbench I designed and had CNC cut at the same time:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_10_bed/workbench.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;(The bed has MFT-style 20mm holes on 96mm centers, since I figured that if something went wrong during the CNC operations, I might as well end up an extra workbench top.)&lt;/p&gt;

&lt;p&gt;Each leg is a pair of panels, with the inside one cut short for the mattress.
The panels joined through the headboard/footboard with, uh, 3D-printed spacers and tube:&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; margin: auto; max-width: 100%;"
     src="/newsletter/2025_10_bed/bed_legs.jpg"
     alt=""
     /&gt;&lt;/p&gt;

&lt;p&gt;So far it seems to be holding up just fine; no idea how to delegate credit between PCTG&amp;rsquo;s stronger-than-PLA layer adhesion, the bearing friction of the spacers, and the axial metal screw within the tubes.&lt;/p&gt;

&lt;p&gt;On the front of the legs, the tubes are hidden by brass cabinet pulls (which also serve as the nut into which the axial screw clamps the assembly tight).&lt;/p&gt;

&lt;p&gt;Next I expect we&amp;rsquo;ll build some attachments for the bed like a large padded headboard, side table cup holders, plant stands, jacket hangers, etc.&lt;/p&gt;
&lt;h2 id='fan-troubles'&gt;&lt;a class='anchor' href='#fan-troubles'&gt;Fan troubles&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I used my &lt;a href="/papr/"&gt;powered air respirator&lt;/a&gt; while finishing the bed, but I found it a bit stuffy and so I&amp;rsquo;ve been trying to increase the airflow.
I don&amp;rsquo;t have a great way of quantifying the airflow directly, so as a proxy I&amp;rsquo;ve used an &lt;a href="https://amzn.to/4fJOhBl"&gt;FNB58 inline USBC tester&lt;/a&gt; to measure the power consumption of the fan running at full power for one minute.&lt;/p&gt;

&lt;p&gt;Here are the results:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;BFB1012H  0.214 Wh unimpeded
          0.118 Wh filter and hose

BFB1012UH Unable to run, draws too much current from powerbank even at lowest setting

BFB1012VH 0.213 Wh unimpeded
          0.091 Wh filter and hose
          0.101 Wh adapter (no filter) and hose
          0.106 Wh dual adapter (no filters) and hose
          0.113 Wh dual adapter but no hose.
          0.117 Wh hose only
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I started with the &amp;ldquo;H&amp;rdquo; fan, but it felt stuffy so I bought the &amp;ldquo;UH&amp;rdquo; variant based on the &lt;a href="https://nl.aliexpress.com/item/32800276165.html?gatewayAdapt=glo2nld"&gt;AliExpress listing&lt;/a&gt;&amp;rsquo;s description: &amp;ldquo;super violent turbo blower&amp;rdquo;.
Unfortunately, this turned out to draw too much current: nominally it&amp;rsquo;s 6A at 12 V =&amp;gt; 72 W, and even at the lowest PWM speed it still triggers some kind of overcurrent shutdown mode in my USB-C power bank (rated at 22.5W, oops).&lt;/p&gt;

&lt;p&gt;So then I ordered the &amp;ldquo;VH&amp;rdquo;, but from what I can tell it&amp;rsquo;s no better than the original &amp;ldquo;H&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;It seems like the airflow restrictions caused by the filter adapter and/or hose limit the fan to about half the power consumption of the unencumbered fan, which presumably means the airflow is substantially less than the rated capacity.&lt;/p&gt;

&lt;p&gt;What should I try next?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A different model of centrifugal-style blower fan?&lt;/li&gt;
&lt;li&gt;Pairing up two fans I already have into a single (larger?) hose?&lt;/li&gt;
&lt;li&gt;A totally different style of fan?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know about moving air, I&amp;rsquo;d love to hear from you!&lt;/p&gt;
&lt;h2 id='my-rss-feed'&gt;&lt;a class='anchor' href='#my-rss-feed'&gt;My RSS feed&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Did you know my website has &lt;a href="https://kevinlynagh.com/feed.xml"&gt;an RSS feed&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ivanish.ca/"&gt;My friend Ivan&lt;/a&gt; reported that occasionally the items would all show up as &amp;ldquo;unread&amp;rdquo; in his RSS reader.
I&amp;rsquo;ve dug into the issue, which turned out to be related to deploying my website/newsletter from different timezones &amp;mdash; the static site generator I use calls Ruby&amp;rsquo;s &lt;code&gt;Time.parse&lt;/code&gt; method, which always parses into a local datetime.
Luckily this carefree, just-do-something dynamic language attitude also makes for an easy fix:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# from https://github.com/nanoc/nanoc/blob/1955f7c0bc86de9ad51b4bb62530754c65bc9e61/nanoc/lib/nanoc/helpers/blogging.rb#L250-L263&lt;/span&gt;
&lt;span class="c1"&gt;# modified so that the date is always assumed to be UTC midnight, so that published item IDs don&amp;#39;t change as my laptop changes time zones while I&amp;#39;m traveling.&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Nanoc::Helpers&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Blogging&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attribute_to_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;+00:00&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;4.11.6&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;Gem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loaded_specs&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;nanoc&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;
  &lt;span class="kp"&gt;throw&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Nanoc version changed, check that feed id duck punching works.&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;h2 id='misc-stuff'&gt;&lt;a class='anchor' href='#misc-stuff'&gt;Misc. stuff&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;McMaster-Carr now does &lt;a href="https://www.mcmaster.com/info/delivery/"&gt;international deliveries&lt;/a&gt; !!!!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=RppnQ28BsiE"&gt;How CLEVER Design Made Antennas Disappear&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://minarcik.com/minkowski-penalties/"&gt;Minkowski Penalties&lt;/a&gt;: Robust Differentiable Constraint Enforcement for Vector Graphics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=0PF0Ik6luYs"&gt;The Sushi Robots&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.teamten.com/lawrence/programming/checkboxes/"&gt;Don&amp;rsquo;t Use Checkboxes&lt;/a&gt; - the UI parallel to the common advice for programmers, &amp;ldquo;don&amp;rsquo;t use booleans&amp;rdquo;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.grug.design/know"&gt;grug make design&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://arstechnica.com/gadgets/2025/09/your-very-own-humane-interface-try-jef-raskins-ideas-at-home/"&gt;Your very own humane interface: Try Jef Raskin’s ideas at home&lt;/a&gt;. Raskin&amp;rsquo;s book on &lt;a href="https://amzn.to/4no4rD6"&gt;The Humane Interface&lt;/a&gt; is one of my favorites.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://sean-parent.stlab.cc/papers/2015-10-26-gpce/gpce15main-mainid43-p-e08bb9a-25371M-final.pdf"&gt;Generating Reactive Programs for Graphical User Interfaces from Multi-way Dataflow Constraint Systems&lt;/a&gt; While investigating constraint languages, I ran into this paper on &amp;ldquo;Property Models&amp;rdquo;, which are used within Adobe to wire up the gazillion interacting options of, e.g., Photoshop&amp;rsquo;s &lt;em&gt;export image&lt;/em&gt; dialog.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://quaoar.su/blog/page/maas-geometric-kernel"&gt;Geometric kernel for digital manufacturing&lt;/a&gt; &amp;ldquo;The same goes for CAD feature recognition: you do not need a large, overly trained language model to understand that a bottom face is concavely connected to a contour of perpendicular walls. [&amp;hellip;]  the real intelligence here will likely be avoiding anything &amp;lsquo;artificial&amp;rsquo; in a well-defined geometric problem.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=Meal_AzkORM"&gt;The Story of MY Woodshop Design&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://www.youtube.com/watch?v=wyu_V-T4p98"&gt;Kia PV5&lt;/a&gt; is an awesome-looking electric van with great visibility and 100W USB-C sockets on a durable plastic dash; it starts around $45k, and I&amp;rsquo;m looking forward to renting weekend camper conversions of this guy soon.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
</feed>
