Shellsharks Blogroll - BlogFlock 2026-05-14T14:28:20.128Z BlogFlock Adepts of 0xCC, destructured, fLaMEd, Trail of Bits Blog, Aaron Parecki, Westenberg, James' Coffee Blog, gynvael.coldwind//vx.log (pl), joelchrono, Evan Boehs, cool-as-heck, Kev Quirk, Posts feed, Sophie Koonin, cmdr-nova@internet:~$, <span>Songs</span> on the Security of Networks, Johnny.Decimal, Werd I/O, Robb Knight, Molly White, Hey, it's Jason!, Terence Eden’s Blog 52 actionable posts about building a culture of innovation - Werd I/O 6a05bf302bc38300013f3a5e 2026-05-14T12:25:20.000Z <p>Link: <a href="https://pointc.co/the-first-year/?ref=the-idea-bucket-newsletter"><em>The First Year, by Corey Ford at Point C</em></a></p><p>I could include Corey&#x2019;s posts in my <a href="https://werd.io/tag/links">link roundups</a> every single week. Each one is genuinely gold &#x2014; and I&#x2019;ve had the pleasure of knowing and working with Corey in various ways for over a decade, so I also know they work. I use many of them in my own day-to-day practice, and I&#x2019;ll have them front of mind as I move on to my next chapter later this year.</p><p>I also want to say: posting every week on the same day, at the same time, for a whole year is an achievement in itself. I&#x2019;ve been blogging since 1998 and I&#x2019;m not convinced I&#x2019;ve <em>ever</em> been that consistent. As he says, consistency compounds:</p><blockquote>&#x201C;I embraced constraints and forced myself to ship every week, without a long-term plan. Half sheet by half sheet. The first few posts felt like shouting into the void. (And if I&apos;m being honest, I sometimes still wonder whether anyone has time to read these long posts at all.) But then I would run into someone in person at a conference. Or I would catch up with an old student on Zoom. And I would hear the same thing, over and over: Thank you for sharing these frameworks. I just sent our latest one to my team.&#x201D;</blockquote><p>I&#x2019;ve been quietly sharing his posts in our internal #product-reads channel on Slack, which I set up to share links that I think are either inspiring or will be useful in our work. I&#x2019;ve been in board meetings at other orgs where his work has come up organically and I&#x2019;ve been able to enthusiastically +1. If you&#x2019;re not following him, there&#x2019;s still time to correct that. He&#x2019;s the real deal, has changed my life <em>multiple</em> times, and has been similarly influential for others. And if you get a chance to work with him, <a href="https://pointc.co/connect/?ref=werd.io">including as a coach</a> or <a href="https://pointc.co/tag/programs/?ref=werd.io">a consultant for your team and culture</a> &#x2014; run at it.</p> A nice surprise in Things - Johnny.Decimal https://johnnydecimal.com/blog/0196-a-nice-surprise-in-things/ 2026-05-14T03:22:32.000Z <p>After 6 months of following the process from the <a href="https://johnnydecimal.com/jdu/taskpm/">Task and Project Management</a> course, the only item in my <a href="https://culturedcode.com/things/">Things</a> Today view was my start-the-day routine. No category reviews or other cruft. A treat. 😃</p> <p>I&#39;ve been diligent about pushing less-important category reviews out to a longer repeat interval. They must have &#39;shaken out&#39; to the right cadence now. I didn&#39;t want to get review fatigue – I&#39;d rather see them less, but spend quality time when we&#39;re together.</p> <p>And I&#39;m getting better at not dumping tasks in Today and letting them pile up because everything is urgent (it&#39;s not) and I&#39;ll do it all today (I won&#39;t). I&#39;m careful with Today now and try to schedule achievable to-dos so it (me) doesn&#39;t get sad.</p> <p>It&#39;s weird that I don&#39;t have <em>any</em> to-dos in there though. But we just finished a big project so I&#39;m being nice to myself this week.</p> <figure class="figure jdimage jdimage--auto-dark jdimage--drop-shadow"> <picture> <img class="figure__inner" alt="A screenshot of Lucy's Today view in the Things app with only her start-the-day routine showing." fetchpriority="high" height="491" loading="eager" src="https://johnnydecimal.com/blog/0196A-Lucys-Things-with-nothing-in-it-1512x982@2x.png" width="756"> </picture> <figcaption class="figure__caption"> Figure 0196A. An almost-empty Today view in Lucy&#39;s Things app - what a treat. </figcaption> </figure> <h2 id="this-left-me-feeling-organised-and-smug">This left me feeling organised and smug</h2> <p>Until I went to join our first <a href="https://johnnydecimal.com/sbs/">Small Business</a> Zoom call at 6am. And Zoom wouldn&#39;t let me in until I&#39;d done a large software update that took ages. And made me late and feel unprofessional. Now I&#39;m the annoying person on Zoom who isn&#39;t organised (my sincere apologies to Lyra).</p> <p>And so I return to my Things-safety-net with my tail between my legs and add a new repeating task in <code>14 Technology</code> so it won&#39;t happen again.<sup><a href="#user-content-fn-safety-net" id="user-content-fnref-safety-net" data-footnote-ref="" aria-describedby="footnote-label" class="footnote">1</a></sup></p> <figure class="figure jdimage jdimage--auto-dark jdimage--drop-shadow"> <picture> <img class="figure__inner" alt="A screenshot of Lucy's Things app with a new repeating task that says Open Zoom regularly and ensure it’s up to date, or else." fetchpriority="high" height="864" loading="eager" src="https://johnnydecimal.com/blog/0196B-Lucys-new-repeating-reminder-cropped-1890x1728@2x.png" width="945"> </picture> <figcaption class="figure__caption"> Figure 0196B. A new repeating task to ensure Zoom stays up to date. </figcaption> </figure> <div data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2> <ol> <li id="user-content-fn-safety-net"> <p>Note that this repeating task will always appear in Today even if the overall category-review interval for <code>14 Technology</code> isn&#39;t as often. <a href="#user-content-fnref-safety-net" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref footnoteBackLink">↩</a></p> </li> </ol> </div> How Many Mildliner Colours Are There, Really? - Robb Knight • Posts • Atom Feed https://rknight.me/blog/how-many-mildliner-colours-are-there-really/ 2026-05-13T19:03:06.000Z <p>This is, in fact, <em>another</em> post about how many colours of Mildliners there are but it should be the final one of this format. Last week I posted about <a href="https://rknight.me/blog/how-many-mildliner-mix-colours-are-there/">the Mildliner mix colours</a> in which I said I was going to look into redoing my <a href="https://mildliners.rknight.me/">Mildliner reference site</a> and I've done just that with version two.</p> <figure><img src="https://cdn.rknight.me/site/2026/mildliner-types.jpg" alt="The logos for all the types of Mildliner pens" /></figure> <blockquote> <p>That right there is the mildliner colours. Now let's talk about the mildliner colours. Can we talk about the mildliner colours please, Mac? I've been dying to talk about the mildliner colours with you all day, okay?</p> </blockquote> <p>Version two of the site includes:</p> <ul> <li>The colours and sets for all Mildliner types: standard, brush, fine, mix, dot, stamp, and fragrance</li> <li>SVGs of every pen type — the clips and length are different on all of them</li> <li>New SVG logos for all the pen types because Zebra don't appear to have these anywhere</li> <li>Icons for the pen types to use with the colour list</li> <li>All 42 colours (more on that below) with indicators of which types they are available with</li> <li>Print stylesheets for printing checklists of sets</li> </ul> <figure><img src="https://cdn.rknight.me/site/2026/mildliner-type-indicators.jpg" alt="All the yellows available in Mildliners with icon indicators to say which types those colours exist in" /></figure> <p>While looking for something else I noticed on <a href="https://www.zebrapen.com/pages/discover-mildliner-new">this page on Zebra's website</a><sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> that they say there are 42 colours which is one less than the 41 I was aware of. I looked through the list and none of them seemed unfamiliar so I started writing them out one by one until I found it — deep gray, which I had overlooked on my first pass, is a new colour that only exists in the <a href="https://rknight.me/blog/mildliner-fine-review/">Mildliner fine pens</a>. I had misidentified the deep gray as dark gray in my review — I got <em>really close</em> to noticing and then didn't:</p> <blockquote> <p>[...] all the cap colours match with the exception of dark grey where the cap is much darker on the fine one than it's standard counterpart.</p> </blockquote> <p>Version two of the site has been a bunch of work to find out all the information - Zebra has different information depending on the country so it's been hard to trakc down some of it. I'm still looking to find out the Japanese product codes of the Mix colours but I'm hoping I'll have mine by next week to confirm that. I also believe the Dot and Stamp markers don't exist in the Japanese market so they don't have the product codes.</p> <p>I'm pretty happy with the whole site but the &quot;All Colours&quot; section is my favourite — each colour shows, with custom icons, which pen type the colour is available with. Fun fact: Gold and Apricot are the only two colours that are available in every pen type.</p> <p><a href="https://mildliners.rknight.me">Mildliner Reference Version Two</a></p> <hr class="footnotes-sep" /> <section class="footnotes"> <ol class="footnotes-list"> <li id="fn1" class="footnote-item"><p>Notice the hilarious <code>-new</code> on the slug and the title of the page is &quot;Copy of Discover Mildliners&quot;. The <a href="https://www.zebrapen.com/pages/discover-mildliner">old page</a> still exists <a href="#fnref1" class="footnote-backref">&#10558;</a></p> </li> </ol> </section> AI may be the new gatekeepers, but human connection is more needed than ever - Werd I/O 6a046b54ef485b0001c83fdd 2026-05-13T12:15:16.000Z <p>Link: <a href="https://newpublic.org/afterthefeed?ref=werd.io"><em>After the Feed, by New_ Public</em></a></p><p>I think this research-based presentation about the future of the information ecosystem in the age of AI is important for publishers, product leaders, and social platform builders to read and understand. If you assume that AI <em>will</em> dominate how people receive their information, its conclusions are sensible, well thought-through, and even optimistic in some ways. I think all signs &#x2014; AI adoption curves, data about social media use, qualitative evidence about how people are using AI to gather information today &#x2014; point to the fact that it will.</p><p>This is the crux:</p><blockquote>&#x201C;Agentic interfaces are the new intermediaries for information about the world around you. This looks like a chat with Claude or a briefing from your personal AI agent &#x2014; an interface built for an audience of one.<br><br>These agentic interfaces will increasingly become the nexus through which you access information and connection.&#x201D;</blockquote><p>For me, the framing of AI&#x2019;s effects on existing information ecosystems while it establishes a new one was helpful. It&#x2019;s, frankly, brutal: social networks, other online spaces, and the web itself are getting filled with bots and slop as people compete for engagement and eyeballs. In these spaces, AI-powered harassment, doxxing, and cheap, automated content are becoming more prevalent, while AI models are simultaneously making it easier to extract signal from those same spaces.</p><p>AI vendors are clearly the &#x201C;<em>new</em> new gatekeepers&#x201D;. Like the previous ones, they will dominate how we learn about the world even while some of us turn to open source and liberatory alternatives. But they may not dominate how we <em>connect</em> and <em>share</em> our experiences of the world, and that&#x2019;s the core of the opportunity: how do we design pro-social frameworks and spaces that sit alongside an agentic information ecosystem?</p><p>I&#x2019;m biased towards New_ Public&#x2019;s point of view: pro-social spaces, pro-democracy technology, and community as an ingredient for trust are all my jam. But everything laid out in this presentation is already happening. People are already getting AI-generated information summaries; they are already retreating into trust-based group chats and small spaces; much more software is already being produced, straining platforms like GitHub; social platforms are already declining. But the opportunities are genuinely emerging too: I&#x2019;ve <a href="https://werd.io/one-size-fits-none-let-communities-build-for-themselves/">written before about the opportunity for open protocols as building a foundation for bespoke micro-communities</a>, and the core need on the internet has always been to connect with other people.</p><p>How this plays out is not yet written, although new defaults are currently being established by the AI vendors. We need more research, more experimentation, and more dedicated space to explore pro-social spaces, trust, and connection. And we need builders. Communities and trust are going to be very central to my work and research over the next year; I&#x2019;m grateful for this encapsulated research, which I think will help to guide us all.</p> Stupidly Simple SVG Sparklines - Terence Eden’s Blog https://shkspr.mobi/blog/?p=63359 2026-05-13T11:34:01.000Z <p>A sparkline is a little line-graph with no axes or other unnecessary details. They're useful for getting quick understanding of what the data is showing.</p> <p>They're also <em>really</em> easy to create programmatically.</p> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 124"><polyline fill="none" stroke="#0074D9" stroke-width="3" points="12,48 83,84 154,79 226,90 297,79 369,65 440,78 512,80 583,88 654,12 726,56 797,92 869,93 940,97 1012,106"></polyline></svg> <p>This uses the SVG "<a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polyline">polyline</a>" which takes a list of x,y co-ordinate pairs. But can you spot the small problem?</p> <pre><code class="language-svg">&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 124"&gt; &lt;polyline fill="none" stroke="#0074D955" stroke-width="3" points="12,48 83,84 154,79 226,90 297,79 369,65 440,78 512,80 583,88 654,12 726,56 797,92 869,93 940,97 1012,106"&gt;&lt;/polyline&gt; &lt;/svg&gt; </code></pre> <p>The SVG co-ordinate system has position 0,0 at the top <em>left</em>. Most graphics formats are like that. That's fine for our x value - but it means higher y values will appear <em>lower</em> on the graph.</p> <p>Getting the x co-ordinate of each data point is easy. Take the width of the SVG image and divide it by the number of data-points.</p> <p>The y co-ordinate is harder. The algorithm is:</p> <ol> <li>Find the height of the SVG.</li> <li>Find the maximum value in the data.</li> <li>Find the minimum value in the data.</li> <li>Divide the maximum value by the height of the graph.</li> <li>For each data point, either: <ul> <li>To have the lowest value at the bottom of the graph, subtract the minimum from the value, then multiply by the ratio in (4).</li> <li>Or, to retain the gap between zero and the lowest value, multiply the value by the ratio in (4).</li> </ul></li> <li>The y co-ordinate is calculated by subtracting the value in (5) from the height in (1).</li> </ol> <p>Here's some code showing how it works. I've added a little padding to the inside of the graph - you'll see why later:</p> <pre><code class="language-php">// Max and min of views. $max_views = max( $svg_views_data ); $min_views = min( $svg_views_data ); $svg_data_length = sizeof( $svg_dates_data ) - 1; // SVG details for scaling. $svg_padding = 12; $svg_width_graph = 1000; $svg_width = $svg_width_graph + ( $svg_padding * 2 ); $svg_height_graph = 100; $svg_height = $svg_height_graph + ( $svg_padding * 2 ); // Calculate where each point should be. $x_per = $svg_width_graph / ( $svg_data_length ); $y_per = $svg_height_graph / $max_views; // Loop through the data. foreach ( $svg_views_data as $index=&gt;$views ) { // X is from the left. $x_pos = intval( $x_per * $index ) + $svg_padding; // Y is from the top. $y_pos = $svg_height - intval( $y_per * $views ) - $svg_padding; // Add a point to the line. $polyline_points .= "{$x_pos},{$y_pos}\n"; } echo &lt;&lt;&lt; SVG &lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 $svg_width $svg_height" class="chart"&gt; &lt;polyline fill="none" stroke="#F00" stroke-width="3" points="{$polyline_points}"/&gt; &lt;/svg&gt; SVG; </code></pre> <p>Suppose someone suggests stupidly simple sparklines suffer seriously so someone should supplement statistics several circles?</p> <p>Using the same co-ordinates, we can place an SVG circle on top of the point. Give it a "title" attribute and you have a little bit of interactivity.</p> <pre><code class="language-svg">&lt;circle cx="12" cy="48" r="5" fill="#0074D955"&gt;&lt;title&gt;4,707 Views&lt;/title&gt;&lt;/circle&gt; </code></pre> <p>Here's how it looks (view source to understand how it is constructed).</p> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 124" class="chart"> <polyline fill="none" stroke="#0074D9" stroke-width="3" points="12,48 83,84 154,79 226,90 297,79 369,65 440,78 512,80 583,88 654,12 726,56 797,92 869,93 940,97 1012,105 "></polyline> <circle cx="12" cy="48" r="5" fill="#0074D955"><title>4,707 2025-09-01</title></circle><circle cx="83" cy="84" r="5" fill="#0074D955"><title>2,051 2025-09-02</title></circle><circle cx="154" cy="79" r="5" fill="#0074D955"><title>2,444 2025-09-03</title></circle><circle cx="226" cy="90" r="5" fill="#0074D955"><title>1,627 2025-09-04</title></circle><circle cx="297" cy="79" r="5" fill="#0074D955"><title>2,450 2025-09-05</title></circle><circle cx="369" cy="65" r="5" fill="#0074D955"><title>3,453 2025-09-06</title></circle><circle cx="440" cy="78" r="5" fill="#0074D955"><title>2,491 2025-09-07</title></circle><circle cx="512" cy="80" r="5" fill="#0074D955"><title>2,326 2025-09-08</title></circle><circle cx="583" cy="88" r="5" fill="#0074D955"><title>1,754 2025-09-09</title></circle><circle cx="654" cy="12" r="5" fill="#0074D955"><title>7,268 2025-09-10</title></circle><circle cx="726" cy="56" r="5" fill="#0074D955"><title>4,113 2025-09-11</title></circle><circle cx="797" cy="92" r="5" fill="#0074D955"><title>1,503 2025-09-12</title></circle><circle cx="869" cy="93" r="5" fill="#0074D955"><title>1,394 2025-09-13</title></circle><circle cx="940" cy="97" r="5" fill="#0074D955"><title>1,108 2025-09-14</title></circle><circle cx="1012" cy="105" r="5" fill="#0074D955"><title>533 2025-09-15</title></circle></svg> <p>Hover over any of those little circles and you'll see some pop-up text giving you information about that datapoint.</p> <p>…that's it! If you have an array of data points, you can easily create a graph with no graphing library, no plugins, no 3rd party dependencies. Just super simple SVG.</p> <img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=63359&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager"> New bike, childhood movies, and origami for once! - Joel's Log Files https://joelchrono.xyz/blog/2026-w19 2026-05-13T03:10:40.000Z <p>This week was definitely characterized by a return to a lot of nostalgic things. No complaining, you will see what I mean as you read :P</p> <ul> <li> <p>🤱 It was Mother’s Day in México! I feel bad because I didn’t do breakfast for my mom. But the rest of the day was good nonetheless. It was on Sunday so my church had a special events to honour all the mothers. Kids, teens and youth all participated, be it in choir, and there was also a play! Of course everyone helped prepare lunch and help in any way so the moms could just relax and chats. My siblings called later and we had our own fun too talking with mom.</p> </li> <li> <p>🚲 I have a new bike, used from a local bike repair shop. There were many options but I went for a hybrid (a Fuji Traverse 1.6 for those curious), fit for city but with slightly wider wheels that can handle light dirt and gravel paths. I got it after work, stepping off the bus transport much earlier than usual since the shop was halfway through. They let me do a test ride around the block and it was love at first sight. Since I had no car I had to ride all the way home from there! It was 7 kilometer journey and I actually pulled it off very easily. Since then I’ve just been having fun riding on my patio, but I am yet to bike through the city again. I am considering commuting to work with it, but I’ll have to write down some thoughts about all this later.</p> </li> <li> <p>🚗 My parents went on a trip last weekend and returned right after I had purchased the bike, I didn’t want to not tell them about it so I brought it up and they were a bit confused as to where a bike would fit in my daily life. Again, I’ll write about that later, the point is they didn’t get mad lol.</p> </li> <li> <p>📷 I returned to do an actual origami for no particular reason, for the first time in a while. I folded a “Dollar Camera”—a camera model that can be made with a dollar bill—by Won Park. The model is incredibly simple and very fun to do, I had it memorized for years and as soon as I started following the diagram it all rushed back to me. I should upload a pic to the website soon.</p> </li> <li> <p>🛡️ I got an unexpected gift from Limited Run Games/Falcom. Since the physical release of <em>Trails in the Sky 1st Chapter</em> was delayed when I preordered it. They gave a pin to every buyer! I actually wasn’t expecting something so cool to show up.</p> </li> </ul> <h2 id="watching">Watching</h2> <p>As I said, this was a week full of nostalgia, and as such, I decided to revisit three films that were a part of my childhood and even teenage years. I am a huge fan of this franchise and I will probably write a long blogpost about it because <em>Max Steel</em> is the best action figure ever, and one of my favorite heroes of all time.</p> <ul> <li> <p><strong>Max Steel: Endangered Species</strong> - The first animated film of the franchise, featuring worse graphics than early PS2 cutscenes, a soundtrack by Brian Carston that goes <em>way too hard</em> for a movie made to sell toys, a hero that needs to inject himself with some drug to survive, and some incredible scenes for fans of the series, the two main villains of the TV show, Biocon and Psycho, team up to destroy the world, there’s a chase down an ice peak at night, and an epic final fight on top of Mayan ruins. I have to be honest, even though the graphics are dated, the animation quality, mostly done with motion capture, is really amazing, especially that fight choreography with that epic music, the voice acting of the Latino dub is awesome as well!</p> </li> <li> <p><strong>Max Steel: Forces of Nature</strong> - The previous movie teased Max Steel’s upcoming villain, and this guy is genuinely terrifying. Elementor, a clone of Biocon, has the ability to control the Elements: Water, Earth, Wind, Fire and Metal—this guy showed up before Avatar The Last Airbender, by the way. And wants to terraform the world to his will. Max Steel must do everything he can to stop him from acquiring full strength, but is bested at every moment. There are revelations, there is betrayal, and there’s an epic moment surfing the eye of a tornado.</p> </li> <li> <p><strong>Max Steel: Countdown</strong> - This was the last movie I watched, but the first I ever saw as a child. Elementor is back, and this time he has divided itself into five, one for each element! As they attach to the planet’s core, the terraformation is already in progress, and Earth won’t be able to sustain life in a matter of hours. Max Steel will challenge them one more time, will he be able to defeat them? Yes, with a bicycle kick of all things!</p> </li> </ul> <p>I have so much more to say about these films, but I’ll just write a separate post to be honest. Absolute childhood nostalgia.</p> <h2 id="gaming">Gaming</h2> <ul> <li> <p>🥐 <strong>CrossCode</strong> - Finally had time to return to this gem of a game, I have been playing the last of three dungeons in the current chapter I’m playing. I’ve managed to get the key to the boss room now, after some very very complicated looking puzzles. I had a lot of fun! The block puzzles and pinball style mechanics continue to amuse me to no end here</p> </li> <li> <p>👾 <strong>UFO 50</strong> - I “returned” <strong>Barbuta</strong>, unable to beat it in time. I think it’s a great game with some neat elements going for it, but I am just too used to the easy life of modern titles! Anyway, now I am playing <strong>Bug Hunter</strong>, it’s a title that reminds me of a very bare-bones <em>Into The Breach</em>, killing bugs in a grid using a limited set of actions. I can get more actions by getting energy, but killing enemies doesn’t give energy, so I have to choose the path and order of things, be smart about it. It’s challenging! But I’ll keep trying.</p> </li> <li> <p>🐉 <strong>Monster Hunter Freedom Unite</strong> - For the same childhood nostalgia I felt inclined to go for a Tigrex hunt on my PSP! I just chose the village quest and went with my G rank gear because I just wanted to have some easy fun avoiding attacks without having to get carted due to a simple mistake. In any case this game remains extremely fun!</p> </li> <li> <p>🏝️ <strong>Tomodachi Life: Living the Dream</strong> - I’ve been leveling up Miis and having some fun keeping them in check. Not a lot of updates but I’ve seen some new scenes and funny moments showing up, as well as the news everyday which are always pretty entertaining.</p> </li> </ul> <h2 id="reading">Reading</h2> <ul> <li> <p><strong>Tiamat’s Wrath</strong> - I finally finished… the prologue. And a bit of the first chapter!</p> </li> <li><strong>Heavenly Delusion</strong> - Up to chapter 53. The protagonists met some of the other protagonists at once, gave closure to some mysteries, and are about to face a giant monster heading to a city of survivors getting by.</li> <li><strong>Shikimori’s Not Just A Cutie</strong> - Up to chapter 108.</li> <li><strong>Spy x Family</strong> - Up to chapter 134.</li> <li><strong>Blue Lock</strong> - Up to chapter 345.</li> </ul> <h2 id="around-the-web">Around the Web</h2> <h3 id="blogposts">Blogposts</h3> <ul> <li> <p><a href="https://jamesg.blog/2026/05/07/writing-a-blog-post-without-a-screen">Writing a blog post without a screen</a> - I’ve written a blogposts by hand in cursive but this is kinda crazy.</p> </li> <li> <p><a href="https://schafe-sind-bessere-rasenmaeher.de/posts/we-got-a-new-bike/">We got a new bike!</a> - I was not the only one purchasing a bike! This one is pretty cool with lots of space to carry things (and kids!)</p> </li> <li> <p><a href="https://orbitalmartian.vercel.app/blog/2026-05-09-spicing-up-my-website/">Spicing Up My Website</a> - Wooo, always nice when a friend adds some to his blog. Pixel bear yay!</p> </li> <li> <p><a href="https://brainbaking.com/post/2026/05/another-triumph-for-blogging/">Another Triumph For Blogging</a> - Wouter met a fellow blogger IRL, that is super cool.</p> </li> </ul> <h3 id="youtube">YouTube</h3> <ul> <li><a href="https://youtu.be/5EE8m8mmq1k">Casually Explained: Cycling</a> - A short animation comedy about cycling and commuting and the like, kinda funny but with some edgy humor</li> <li><a href="https://youtu.be/j0SiHB2Q780">I Tried Mountain Bike Commuting - How Does it Compare to a Road Bike?</a> - This was actually a very relaxing video to watch, just a POV of a commute! It has some cuts but it’s pretty nice. Japan is cool.</li> <li><a href="https://youtu.be/GhAU5o2TK5g">Are you bike commuting wrong? Fitness vs transportation explained</a> - Neat tips to take. I am worried about commuting to work and especially sweat on my back but maybe it’s not so bad.</li> <li><a href="https://youtu.be/umgi-CbaSRU">Every Reason to Hate Cars</a> - This is a long one, Not Just Bikes is a great channel that I’ve shared videos of before.</li> <li><a href="https://youtu.be/BYVVE0D6In0">What a Bicycle Shop in Japan is Like</a> - A fun tour on a bike shop in Japan, I love the variety and the types there are over there. Very interesting.</li> <li><a href="https://youtu.be/TfcSBcR0JSc">I Built a Bike Out Of Home Depot Supplies</a> - Now this was such a silly project, and yet it worked. It’s wild how things worked out in the end.</li> </ul> <p>This is day 64 of <a href="https://100daystooffload.com">#100DaysToOffload</a></p> <p> <a href="mailto:me@joelchrono.xyz?subject=New bike, childhood movies, and origami for once!">Reply to this post via email</a> | <a href="https://fosstodon.org/@joel/116565091620668305">Reply on Fediverse</a> </p> Position statement: AI-generated apps - Johnny.Decimal https://johnnydecimal.com/blog/0195-position-statement-ai-generated-apps/ 2026-05-13T02:41:53.000Z <p>So that I have an artefact that I can send to people, or link to when I want to explain my position, here&#39;s how I feel about AI-generated apps. If I&#39;ve sent you this link, it isn&#39;t personal. Please don&#39;t take it as such (even though I&#39;ve written it with a heavy dose of snark). :-)</p> <h2 id="before-now">Before now</h2> <p>Before, nobody could make an app. Well, a handful of really specialised software engineers could. But you couldn&#39;t.</p> <p>So, apps were special. An app that did a thing that you needed it to do was probably worthy of attention. Maybe it wasn&#39;t any good, but still: an app! Someone spent <em>hundreds of hours</em> making it. Worth a look.</p> <h2 id="everyone-can-make-an-app">Everyone can make an app</h2> <p>Now, essentially anyone can make an app. <em>Hey Claude, make an app</em>.</p> <p>What does that mean for <em>your</em> app, that you made? It means that I&#39;m probably not going to look at it, and you shouldn&#39;t expect anyone else to care either. Sorry.</p> <p>This might be unfair! You might have made The Best App. But so has everyone else. And everyone else wants people to check out <em>their</em> app and, well, you can see how that doesn&#39;t scale.</p> <h2 id="enjoy-your-own-app">Enjoy your own app</h2> <p>I&#39;m not criticising AI-generated apps. It&#39;s amazing that you can make an app. What a time we live in.</p> <p>But don&#39;t expect anyone else to care. They&#39;re busy. Making apps.</p> Spend time with your own words - Johnny.Decimal https://johnnydecimal.com/blog/0194-spend-time-with-your-own-words/ 2026-05-13T01:39:10.000Z <p>Yesterday me and Lucy spent the day going through categories <code>21 Products (etc.)</code> and <code>31 Marketing (etc.)</code> in our own small business JDex. They&#39;re where the bulk of our stuff is, and they&#39;d been neglected as we spent a few months with our heads down <a href="https://johnnydecimal.com/blog/0193/">rebuilding this site</a>.</p> <p>There&#39;s about 23,000 words across those two folders in maybe 100 separate notes. It was a bit of a chore, honestly. But it needed doing, and I&#39;m glad we did it. Because that&#39;s my business in there. Ideas that I&#39;ve had, patterns, thoughts, notes-for-future-me. Yesterday morning I didn&#39;t really know what was in there. Now I do.</p> <p>I don&#39;t think there&#39;s a way to shortcut that work. I know it can be tempting to get <em>the machine</em> to do it for you, but would that move you forward? Would you now be in a better situation than we were yesterday morning? I don&#39;t think you would be.</p> <p>They&#39;re your words. They&#39;re thoughts that came out of your brain. If they&#39;re worth anything at all, spend some time with them.</p> Growing with my website - James' Coffee Blog https://jamesg.blog/2026/05/13/growing-with-my-website 2026-05-13T00:00:00.000Z <p>At this evening’s <a href="https://indieweb.org/Homebrew_Website_Club" rel="noreferrer">Homebrew Website Club</a>, I asked: What was the biggest change in our websites since we started them? This question was inspired in part by <a href="https://paultibbets.uk/">Paul</a> saying something to the effect of how we build our websites and, in the process, figure out what we want our websites to be.</p><p>There are many lenses through which to think about the question – the technology behind a website, the design of a website <sup class="footnote-reference" id="f-1"><a href="https://jamesg.blog/longform-feed#1">1</a></sup>, the philosophies and goals behind our website, and more. My answer was that a few years ago I started worrying less about posting on lots of different topics, and accepted the joy of putting all my writing in one place.</p><p>The back story is that when I started blogging more about coffee a few years ago, I worried that posts about technology would detract from the coffee posts, and vice versa. I knew people who liked specialty coffee looked at my website and I didn’t want the site to look confusing for someone not interested in technology. I started wondering if I should have a home page that was split with two lists: one for technology posts and another for coffee posts. <sup class="footnote-reference" id="f-2"><a href="https://jamesg.blog/longform-feed#2">2</a></sup> <em>Should I have two different websites?</em></p><p>I can’t remember the exact moment when things changed, but at some point I realised it was okay to put my writing on many subjects in one place <sup class="footnote-reference" id="f-3"><a href="https://jamesg.blog/longform-feed#3">3</a></sup>. I also started to feel more confident in writing about more topics, too. This was a process that unraveled with time and experimentation and play. Part of the fun of having a website is in the growing – of trying new things and realising that there’s even more you can do and continuing to play and experiment. And a lot of that was possible because I saw many other lovely websites and spoke with people who had websites – every website expands my understanding of what a website can be.</p><p>I want my blog to be a slice of my life, and my life is multi-faceted. I love writing and playing guitar and Nature and poetry and listening to Taylor Swift music and writing about technology and thinking about the future of the web and writing down ideas I have and so much more. That is me. And so, a mix of things is what I want my website to be.</p><p>At the time of writing this post, my home page lists posts on <a href="https://jamesg.blog/2026/05/12/walking-6">walking</a>, <a href="https://jamesg.blog/2026/04/01/museum-memories-roundup">museums</a>, <a href="https://jamesg.blog/2026/05/09/serendipity">Nature</a>, <a href="https://jamesg.blog/2026/05/07/writing-a-blog-post-without-a-screen">writing a blog post without a screen</a>, <a href="https://jamesg.blog/2026/05/06/ideas-for-web-readers">ideas for web readers</a>, <a href="https://jamesg.blog/2026/05/06/how-i-use-my-phone">how I use my phone</a>, and more – many of my interests and thoughts and observations and dreams, sitting side by side.</p><p>I do wish I could remember when I realised it was okay to put everything together, but all I can say is that I’m glad I arrived at where I am. I don’t want my blog to be any other way.</p><p>I am curious: What has been the biggest change to your website since you started it? Or, alternatively: how have you changed since you started your website?</p> <div class="footnote-definition" id="1"><sup class="footnote-definition-label" id="f-4">1</sup> <p>This encouraged me to look up when I last redesigned my website. The current design is based on the theme I made in my 2024 redesign. It seems like just yesterday that I redesigned my website. Maybe we need a concept of “website time” to refer to how time feels in relation to our websites.</p> <a href="https://jamesg.blog/longform-feed#f-1">[↩]</a></div> <div class="footnote-definition" id="2"><sup class="footnote-definition-label" id="f-5">2</sup> <p>Back then my blog was mostly about technology and the web and coffee.</p> <a href="https://jamesg.blog/longform-feed#f-2">[↩]</a></div> <div class="footnote-definition" id="3"><sup class="footnote-definition-label" id="f-6">3</sup> <p>My blog is called James’ Coffee Blog because I loved coffee when I gave it that name (and still do, but I drink a lot more tea at the present moment; my website and I both change) and wrote a lot about coffee, but the site grew into so much more. I still like the name because I have been using it for so long, and it represents a slight separation between me and my blog: my blog is part of me, but not all of me.</p> <a href="https://jamesg.blog/longform-feed#f-3">[↩]</a></div> <script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9fb446754a968de5',t:'MTc3ODcwMjY5Nw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&amp;&amp;(document.onreadystatechange=e,c())}}}})();</script> <a class="tag" href="https://indieweb.org/Homebrew_Website_Club">Homebrew Website Club</a> <a class="tag" href="https://jamesg.blog/2026/04/01/museum-memories-roundup">museums</a> <a class="tag" href="https://jamesg.blog/2026/05/06/how-i-use-my-phone">how I use my phone</a> <a class="tag" href="https://jamesg.blog/2026/05/06/ideas-for-web-readers">ideas for web readers</a> <a class="tag" href="https://jamesg.blog/2026/05/07/writing-a-blog-post-without-a-screen">writing a blog post without a screen</a> <a class="tag" href="https://jamesg.blog/2026/05/09/serendipity">Nature</a> <a class="tag" href="https://jamesg.blog/2026/05/12/walking-6">walking</a> <a class="tag" href="https://jamesg.blog/longform-feed#1">1</a> <a class="tag" href="https://jamesg.blog/longform-feed#2">2</a> <a class="tag" href="https://jamesg.blog/longform-feed#3">3</a> <a class="tag" href="https://jamesg.blog/longform-feed#f-1">[↩]</a> <a class="tag" href="https://jamesg.blog/longform-feed#f-2">[↩]</a> <a class="tag" href="https://jamesg.blog/longform-feed#f-3">[↩]</a> <a class="tag" href="https://paultibbets.uk/">Paul</a> Upgrading My Home Internet to Full Fibre - Kev Quirk https://kevquirk.com/upgrading-my-home-internet-to-full-fibre 2026-05-12T18:19:00.000Z <p>As many regular readers know, we live in the North Wales countryside, which means it can take time to get the latest and greatest when it comes to technology.</p> <p>As a result, we were previously "limited" to FTTC (fibre to the cabinet) which had a max speed of 70Mbps. As a result, we got <em>okay</em> internet speeds:</p> <p><img src="https://kevquirk.com/content/images/upgrading-my-home-internet-to-full-fibre/speed-test-before.webp" alt="speed-test-before" /></p> <p>But then I saw the ISP vans in the village, and I asked them what they were doing - <em>"oh, we're upgrading the village to full fibre"</em> she said.</p> <p>I had to have it!</p> <p>As soon as FTTP (fibre to the premises) was available, I placed the order with my ISP (who offered me a great deal that's only £5 per month more), and this is the result:</p> <p><img src="https://kevquirk.com/content/images/upgrading-my-home-internet-to-full-fibre/speed-test-after.webp" alt="speed-test-after" /></p> <h2>Is it worth it?</h2> <p>In all honesty, I haven't noticed the difference. We didn't have any buffering issues when watching things like Netflix or Apple TV, so I'm not really sure why I upgraded in hindsight.</p> <p>I thought it would be this incredible difference where my internet would then be rapid, but the truth is, it's complete imperceptible. I remember when I upgraded from a 56k MODEM, to ~2Mbps broadband and it blew my mind. I was thinking this would be the same, but no.</p> <p>I do think the increased upload speed is going to come in handy when it comes to things like syncing my private <a href="https://kevquirk.com/im-off-github">git repos</a> back to my Synology, but aside from that, there's not much in it.</p> <p>Had I paid full price (~£20 more per month) I don't think I'd have been too happy, but since I got a good deal, I'm not too bothered.</p> <div class="email-hidden"> <hr /> <p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p> <p>You can <a href="mailto:19gy@qrk.one?subject=Upgrading%20My%20Home%20Internet%20to%20Full%20Fibre">reply to this post by email</a>, or <a href="https://kevquirk.com/upgrading-my-home-internet-to-full-fibre#comments">leave a comment</a>.</p> </div> Go fuzzing was missing half the toolkit. We forked the toolchain to fix it. - Trail of Bits Blog https://blog.trailofbits.com/2026/05/12/go-fuzzing-was-missing-half-the-toolkit.-we-forked-the-toolchain-to-fix-it./ 2026-05-12T11:00:00.000Z &lt;p&gt;Go&amp;rsquo;s native fuzzing is useful, but it stands far behind state-of-the-art tooling that the Rust, C, and C++ ecosystems offer with LibAFL and AFL++. Path constraints are hard to solve. Structured inputs usually need handmade parsing. It doesn’t even detect several common bug classes, such as integer overflows, goroutine leaks, data races, and execution timeouts. So to make it better, we built &lt;a href="https://github.com/trailofbits/gosentry"&gt;gosentry&lt;/a&gt;, a fuzzing-oriented fork of the Go toolchain that keeps the standard &lt;code&gt;testing.F&lt;/code&gt; workflow while using a stronger fuzzing stack underneath to tackle those issues.&lt;/p&gt; &lt;p&gt;With gosentry, &lt;code&gt;go test -fuzz&lt;/code&gt; uses LibAFL by default. It can fuzz structs natively, run grammar-based fuzzing with Nautilus, detect bug classes that it couldn’t detect before, and create a fuzzing campaign coverage report in one command.&lt;/p&gt; &lt;p&gt;If you already have Go fuzz harnesses, you don&amp;rsquo;t need to rewrite them. Point them at gosentry&amp;rsquo;s binary and you get all of the above through the same &lt;code&gt;go test -fuzz&lt;/code&gt; interface, with a few new flags:&lt;/p&gt; &lt;figure class="highlight"&gt; &lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./bin/go &lt;span class="nb"&gt;test&lt;/span&gt; -fuzz&lt;span class="o"&gt;=&lt;/span&gt;FuzzHarness --focus-on-new-code&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; --catch-races&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; --catch-leaks&lt;span class="o"&gt;=&lt;/span&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;figcaption&gt;&lt;span&gt;Figure 1: Basic gosentry usage&lt;/span&gt;&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;gosentry keeps the harness API and changes the engine and the surrounding tooling — you just tweak the CLI.&lt;/p&gt; &lt;p&gt;You can also generate coverage reports from an existing campaign with &lt;code&gt;--generate-coverage&lt;/code&gt;. Run it from the same package with the same &lt;code&gt;-fuzz&lt;/code&gt; target, and no corpus path is needed; gosentry stores the campaign state under Go’s fuzz cache index by package and fuzz target, so restarting the campaign resumes from the existing corpus.&lt;/p&gt; &lt;h2 id="why-we-built-gosentry"&gt;Why we built gosentry&lt;/h2&gt; &lt;p&gt;We started this project after we released &lt;a href="https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/"&gt;go-panikint&lt;/a&gt; to improve Go fuzzing’s integer overflow detection. We realized that integer overflow detection wasn’t enough. Go&amp;rsquo;s fuzzing ecosystem was still missing techniques that Rust, C, and C++ researchers already use every day.&lt;/p&gt; &lt;p&gt;We often faced these gaps in our own security work using Go’s vanilla fuzzer:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Program comparisons (path constraints) were impossible to solve: one complex &lt;code&gt;if&lt;/code&gt; branch, and the Go fuzzer could stay stuck forever.&lt;/li&gt; &lt;li&gt;Grammar-based fuzzing was never an option.&lt;/li&gt; &lt;li&gt;Structure-aware fuzzing required additional manual work.&lt;/li&gt; &lt;li&gt;Several Go bug classes would not crash by default or would depend on external libraries, so the fuzzer could reach insecure target behaviors without reporting them.&lt;/li&gt; &lt;li&gt;Generating coverage reports from a fuzzing campaign was cumbersome.&lt;/li&gt; &lt;li&gt;Making the fuzzer crash on critical error logs required manual code changes.&lt;/li&gt; &lt;/ul&gt; &lt;h2 id="same-harness-stronger-engine"&gt;Same harness, stronger engine&lt;/h2&gt; &lt;p&gt;Gosentry keeps the parts Go developers already know:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Write a fuzz target with &lt;code&gt;testing.F&lt;/code&gt;, as usual.&lt;/li&gt; &lt;li&gt;Create your initial corpus with &lt;code&gt;f.Add&lt;/code&gt;.&lt;/li&gt; &lt;li&gt;Pass the input into &lt;code&gt;f.Fuzz&lt;/code&gt;.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Under the hood, gosentry captures the fuzz callback, builds a Go archive with libFuzzer-style entry points, and runs it in-process through a Rust-based LibAFL runner. The API stays familiar, but gosentry enhances the engine, scheduling, detectors, and much more.&lt;/p&gt; &lt;p&gt;We designed it this way to avoid friction for developers and security researchers adopting a new tool. Existing Go harnesses do not need to be ported to a new framework. And since the Go toolchain documentation and usage are already widely integrated into LLM pre-training datasets, an agent can easily use gosentry, as it is a fork of the Go toolchain.&lt;/p&gt; &lt;h2 id="more-bugs-become-visible"&gt;More bugs become visible&lt;/h2&gt; &lt;p&gt;Another added value of gosentry is its capacity to turn more bad behaviors into failures that the vanilla Go fuzzer wouldn’t report.&lt;/p&gt; &lt;p&gt;It includes compiler-inserted integer overflow checks by default and optional truncation checks through the &lt;a href="https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/"&gt;go-panikint&lt;/a&gt; integration. It also lets you choose function calls that should stop the fuzzer. For example, you can use the &lt;code&gt;--panic-on&lt;/code&gt; flag to stop fuzzing when &lt;code&gt;log.Fatal&lt;/code&gt; is called. This flag is useful for codebases that log critical errors and keep going instead of panicking and reporting the bug to the user.&lt;/p&gt; &lt;p&gt;It can also catch data race issues using the native Go race detector (&lt;code&gt;--catch-races&lt;/code&gt;), and goroutine leaks through its &lt;a href="https://github.com/uber-go/goleak"&gt;goleak&lt;/a&gt; integration (&lt;code&gt;--catch-leaks&lt;/code&gt;). Finally, timeouts can be caught at fuzz-time to help detect issues like infinite loops.&lt;/p&gt; &lt;h2 id="better-inputs"&gt;Better inputs&lt;/h2&gt; &lt;p&gt;Gosentry improves input quality in two different ways, which solve different problems.&lt;/p&gt; &lt;h3 id="struct-aware-fuzzing"&gt;Struct-aware fuzzing&lt;/h3&gt; &lt;p&gt;Go&amp;rsquo;s native fuzzing accepts only a small set of parameter types, which doesn’t include composite types, such as structs, slices, arrays, and pointers. Gosentry supports fuzzing of these types.&lt;/p&gt; &lt;!-- markdownlint-disable MD010 --&gt; &lt;figure class="highlight"&gt; &lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;FuzzStructInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fuzz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;figcaption&gt;&lt;span&gt;Figure 2: Supported gosentry harness with structured input&lt;/span&gt;&lt;/figcaption&gt; &lt;/figure&gt; &lt;!-- markdownlint-enable MD010 --&gt; &lt;p&gt;Under the hood, gosentry still mutates bytes. The difference is that it encodes and decodes the composite value for you in a proper way, so you don’t have to invent a custom wire format just to fuzz typed Go inputs.&lt;/p&gt; &lt;h3 id="grammar-based-fuzzing"&gt;Grammar-based fuzzing&lt;/h3&gt; &lt;p&gt;In this mode, gosentry uses &lt;a href="https://github.com/nautilus-fuzz/nautilus"&gt;Nautilus&lt;/a&gt; to generate and mutate grammar-valid inputs while LibAFL still drives the coverage-guided loop.&lt;/p&gt; &lt;p&gt;Let’s imagine you want to fuzz a homemade JSON parser. Without a grammar, most of the time you would generate junk input that wouldn’t even pass the first branches. For example, the fuzzer would mutate &lt;code&gt;{&amp;quot;postOfficeBox&amp;quot;: 123}&lt;/code&gt; to &lt;code&gt;{postOfficeBox&amp;quot;&amp;quot;: &amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;amp;%}&lt;/code&gt;, while a more interesting generated input of &lt;code&gt;postOfficeBox&lt;/code&gt; would be a much larger number like &lt;code&gt;u64.MAX&lt;/code&gt;, giving &lt;code&gt;{&amp;quot;postOfficeBox&amp;quot;: 18446744073709551615}&lt;/code&gt;. In that case, you need grammar-based fuzzing. You define what the structure should be, and the fuzzer generates inputs accordingly. You could write a harness like this:&lt;/p&gt; &lt;!-- markdownlint-disable MD010 --&gt; &lt;figure class="highlight"&gt; &lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;FuzzGrammarJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{&amp;#34;postOfficeBox&amp;#34;:123}`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fuzz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jsonInput&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ParseJSONFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;figcaption&gt;&lt;span&gt;Figure 3: Grammar-based harness for our JSON parser&lt;/span&gt;&lt;/figcaption&gt; &lt;/figure&gt; &lt;!-- markdownlint-enable MD010 --&gt; &lt;p&gt;The grammar format is a JSON array of rules:&lt;/p&gt; &lt;figure class="highlight"&gt; &lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;\\{\&amp;#34;postOfficeBox\&amp;#34;:{Number}\\}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Number&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;{Digit}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Number&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;{Digit}{Number}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;5&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;6&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;7&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;8&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Digit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;figcaption&gt;&lt;span&gt;Figure 4: Definition of our postOfficeBox JSON grammar&lt;/span&gt;&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;Just note that grammar mode still feeds bytes or strings to the harness. So your target needs to be able to parse either strings or bytes.&lt;/p&gt; &lt;h2 id="what-it-has-found-already"&gt;What it has found already&lt;/h2&gt; &lt;p&gt;We’ve been running gosentry on a bunch of targets using grammar-based differential fuzzing campaigns and found a number of bugs. We have disclosed some of these issues to Optimism and Revm:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="https://github.com/ethereum-optimism/optimism/issues/19334"&gt;Unknown batch type panics and causes denial of service in kona-protocol&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="https://github.com/ethereum-optimism/optimism/issues/19333"&gt;Kona and op-node can disagree on brotli channels&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="https://github.com/ethereum-optimism/optimism/issues/19335"&gt;Kona frame parsing mismatch against op-node and OP Stack Specs&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="https://github.com/bluealloy/revm/issues/3458"&gt;Failed deposit in op-revm stopping with &lt;code&gt;OutOfFunds&lt;/code&gt; does not bump nonce, leading to a state root mismatch against other clients&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Those are exactly the kinds of bugs we wanted Go fuzzing to expose. They wouldn’t have been easy to find via the native Go fuzzer, but our grammar-based fuzzer via gosentry was able to easily detect them.&lt;/p&gt; &lt;p&gt;Now, see what you can find. If you already have a Go fuzz target, run it under gosentry and see what it can reach compared to the native Go fuzzer.&lt;/p&gt; &lt;p&gt;The project is available on &lt;a href="https://github.com/trailofbits/gosentry"&gt;GitHub&lt;/a&gt; and includes documentation for each feature described above.&lt;/p&gt; &lt;p&gt;If you’d like to read more about fuzzing, check out the following resources:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Our &lt;a href="https://appsec.guide/docs/fuzzing/"&gt;&lt;strong&gt;fuzzing chapter&lt;/strong&gt;&lt;/a&gt; in the Testing Handbook&lt;/li&gt; &lt;li&gt;&lt;a href="https://blog.trailofbits.com/2024/02/23/continuously-fuzzing-python-c-extensions/"&gt;&lt;strong&gt;Continuously fuzzing Python C extensions&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="https://blog.trailofbits.com/2020/06/05/breaking-the-solidity-compiler-with-a-fuzzer/"&gt;&lt;strong&gt;Breaking the Solidity Compiler with a Fuzzer&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;As always, &lt;a href="https://trailofbits.com/contact/"&gt;&lt;strong&gt;contact us&lt;/strong&gt;&lt;/a&gt; if you need help with your next Go project or fuzzing campaign.&lt;/p&gt; Position or Perish: The Narrative Blueprint - Westenberg 6a02795c65b5c3000191635d 2026-05-12T10:15:17.000Z <img src="https://www.joanwestenberg.com/content/images/2026/05/photo-1714729482484-b88a505bd588.jpeg" alt="Position or Perish: The Narrative Blueprint"><p>Avis was losing $3.2 million a year; and they&apos;d been unprofitable for thirteen straight.&#xA0;</p><p>In 1962, they sat at number two in American car rental, well behind Hertz, with no plausible path to catching up. Robert Townsend, the new president, hired Doyle Dane Bernbach and asked them to do something useful with the worst hand in the industry.</p><p>The campaign DDB produced ran a single line:&#xA0;</p><p><em>&quot;Avis is only No. 2 in rent a cars. So we try harder.&quot;</em></p><p>Within a year, Avis had moved from $3.2 million in losses to $1.2 million in profit. The cars hadn&apos;t changed. The locations hadn&apos;t changed. The pricing hadn&apos;t changed; but the story they told about themselves had, and they let that story do the work.</p><h2 id="what-positioning-is"><strong>What positioning is</strong></h2><p>Positioning is the answer to a question every customer asks before they decide whether to care about your product: &quot;What is this, and why should it matter to me right now?&quot;</p><p>Before you have a product, and well before you have an investor, you need to have an answer to that question - and you need it in a single // simple sentence. Nobody is going to do the cognitive work for you; they&apos;ll categorise your product based on whatever signal they catch in the first three seconds, and the category, once set, is near-impossible to dislodge.</p><p>The category - the box they put you in - determines who you compete with, what price they expect to pay, what features they expect you to have, and what story you&apos;re allowed to tell. Get the category right and you set the terms; get it wrong and you spend the rest of your life arguing with the market about who and what you are.</p><p>Al Ries and Jack Trout published <em>Positioning: The Battle for Your Mind</em> in 1981. The book makes a forty-year-old argument that the war is fought in the customer&apos;s head, where there&apos;s no spare room and no patience for new claims.</p><h2 id="the-most-expensive-mistake-founders-make"><strong>The most expensive mistake founders make</strong></h2><p>The vast majority of founding teams treat positioning as a marketing exercise: Something the marketing team does after the product is built; something you put on the homepage when you&apos;re ready to launch.</p><p>This is both wrong - and expensive.</p><p>Positioning is upstream of marketing. It&apos;s upstream of product, pricing, hiring, fundraising, and PR. It determines what you build, who you sell to, what you charge, and what investors think you are. A company with clear positioning ships faster and raises at higher multiples because every decision flows from the same understood centre.</p><p>A company without clear positioning ships features that contradict each other and hires people who can&apos;t agree on what the company does.</p><p>I&apos;ve worked with companies that had product-market fit and were still failing because no two people inside the building could finish the sentence: &quot;We are the _____ for _____.&quot; When the founders can&apos;t agree, the sales team improvises, and the marketing team writes copy that doesn&apos;t ladder up to anything coherent.</p><h2 id="the-messaging-spine"><strong>The messaging spine</strong></h2><p>Every positioning piece should open with a messaging spine. It&apos;s the series of claims and narrative touchpoints that hold up an entire company. Decks, websites, sales scripts, hiring materials etc all come later.</p><p>A spine has four parts.</p><ol><li>The first is the category. What kind of thing are you? What bucket do you belong in? A category is a shortcut, telling the customer how to think about you in a half-second of attention. If your category is wrong or fuzzy, every downstream message leaks energy trying to fix it.</li><li>The second is the audience. Who is this for, in specifics? &quot;Businesses,&quot; &quot;developers,&quot; and &quot;creators&quot; are broad nouns that fall apart under any pressure. A real audience description names a role and a moment. &quot;Heads of compliance at mid-market fintechs trying to pass their first SOC 2&quot; is an audience. &quot;Modern professionals&quot; is a hallucination.</li><li>The third is the alternative. What are they doing today instead of using you? This is the question most founders skip, and it&apos;s the one that matters most. Customers don&apos;t compare you to nothing. They compare you to the spreadsheet they&apos;ve used for eight years, to the agency they hired last quarter, to the open-source tool they already know, or to the colleague who handled it last month. Until you name the alternative, you can&apos;t claim the wedge.</li><li>The fourth is the wedge. What&apos;s the single sharp thing you do better than the alternative? One thing, expressed so cleanly that a customer can repeat it back to a colleague without stumbling.</li></ol><p>When the spine is right, every other piece of copy in the company writes itself.</p><h2 id="narrative-is-positioning-told-over-time"><strong>Narrative is positioning told over time</strong></h2><p>Positioning is the static claim, but narrative is the moving picture.</p><p>A company can hold a single positioning statement for years, and most should; but the narrative around that statement has to evolve, because the world evolves and your competition evolves with it.</p><p>Stripe&apos;s positioning has been close to constant since 2010: payment infrastructure for the internet. The narrative around it has cycled through a dozen variations; in the early years they talked to developers about seven lines of code. By 2015 they were talking to CFOs about reducing fraud and reconciliation overhead. By 2020 they were telling Fortune 500 boards that they were the operating system for global commerce. But the spine held steady across each story.</p><p>Most companies get this backwards; they keep the narrative fixed and let the positioning drift. The pitch deck still says what it said three years ago, while the product has wandered into a new category and the leadership team is pretending it hasn&apos;t.</p><p>The remedy is to write the spine down, share it with everyone who joins the company, and revisit it once a year with the discipline of a financial audit.</p><h2 id="position-against-something-specific"><strong>Position against something specific</strong></h2><p>Every position works through contrast. The claim says you&apos;re better than something, simpler than something, more honest than something, or designed for someone the alternative ignores.</p><p>When Salesforce launched in 2000, they positioned themselves against &#x201C;software&#x201D; itself. &quot;No software.&quot; Every piece of collateral pointed at the same enemy: installed enterprise software that took twelve months to deploy and cost millions in services. Customers didn&apos;t have to understand SaaS as a category. They had to understand they were tired of waiting for IT to install Siebel.</p><p>Pick your enemy with care. It should be big enough to matter, recognisable enough that customers already have an opinion about it, beatable enough that your wedge works against it, and unable to follow you into the corner you&apos;re claiming.</p><p>The wrong enemy is another startup nobody&apos;s heard of. The wrong enemy is the abstract status quo of &quot;manual processes,&quot; because nobody buys against an abstraction. The right enemy has either a name and a market cap, or a behavioural pattern your audience can picture without effort.</p><h2 id="the-category-gambit"><strong>The category gambit</strong></h2><p>Sometimes the right move is to claim an existing category.</p><p>Sometimes the right move is to invent a new one.</p><p>Inventing a category is harder and more expensive than founders think. The standard venture advice is to &quot;create a new category and dominate it,&quot; and most who try this fail because they don&apos;t have the budget, the airtime, the patience, or the distribution to teach the market a new word.</p><p>When category creation works, it&apos;s because someone with serious distribution put their full weight behind a single term until the market repeated it back. HubSpot did this with inbound marketing. Drift did it with conversational marketing. Gong did it with revenue intelligence. Datadog did it with observability. Each company spent years publishing books and running conferences under a single banner until journalists and analysts stopped questioning whether the category was real.</p><p>If you&apos;re a seed-stage company with $2 million in the bank, you can&apos;t afford to create a category; but you can afford to claim a corner of an existing one, and own it harder than anyone else does. This is the Avis play: you don&apos;t need to invent the rental car. You need to be the company that tries harder than Hertz.</p><p>The category gambit gets misread because the visible examples are the winners. The failed attempts at category creation don&apos;t get studied. For every Drift, there are twenty companies that tried to coin a term, ran out of money before the market adopted it, pivoted into someone else&apos;s category, and disappeared from view.</p><h2 id="what-investors-actually-buy"><strong>What investors actually buy</strong></h2><p>Founders raising venture money tend to treat the pitch deck as a product spec. The deck explains what the product does, how the technology works, why the team is qualified to build it, and how the market is large enough to matter.</p><p>This is also wrong.</p><p>Investors fund stories about products. The deck is a narrative artefact, and its job is to make a partner at a fund repeat your story in a Monday morning meeting without garbling it. If the story collapses when an underprepared partner retells it on three hours of sleep, the deck has failed at the only thing decks exist for.</p><p>The best decks I&apos;ve worked on open with a claim about the world. The product comes in around slide six, after the world has been described in a way that makes the product feel inevitable. Something has changed, something is broken, and the audience half-believes it already but hasn&apos;t seen it written down with any precision.</p><p>Founders skip this because they think the world-claim is obvious. It rarely is, even to the founders who built the company. The investor sees fifteen decks a week and starts each one cold. The first three slides install the worldview that makes everything that follows feel like the logical conclusion of a premise they&apos;ve already accepted.</p><h2 id="copy-as-evidence"><strong>Copy as evidence</strong></h2><p>Every word on the homepage either confirms the positioning or contradicts it. There&apos;s no such thing as neutral copy and there should be no such thing as filler. A hero headline that says &quot;Empower your team&quot; contradicts the positioning of every company that uses it, because the words do no work and the customer has read the same line on a hundred other websites that week.</p><p>Specific words confirm positioning; vague words dissolve it. &quot;We process two billion dollars a year in same-day payouts for marketplaces&quot; is a positioning sentence. &quot;We make payments easy&quot; is a marketing hallucination that any company in the category could have written.</p><p>A good test: take your homepage copy, swap your company name for a competitor&apos;s, and see if the sentences still make sense.</p><p>If they do, you&apos;ve written wallpaper.</p><p>The same test applies to investor decks, sales scripts, hiring pages, and press releases. If a competitor could lift your copy verbatim and use it without changing anything, you&apos;ve written nothing of your own.</p><h2 id="the-pricing-tell"><strong>The pricing tell</strong></h2><p>A consultancy charging $4,000 a month is in a different category from one charging $40,000 a month, regardless of what either website claims. A SaaS product priced at $19 a seat competes in a different market from one priced at $19,000 a year, even when the feature lists overlap. The price tells the customer which competitive set you&apos;re in, and the customer believes the price more than they believe the copy.</p><p>Founders who underprice are doing it because they don&apos;t trust their own positioning. They worry that customers will balk, so they hedge by setting a number nobody could object to. The result is that nobody treats them as serious peers, because cheap reads as low-stakes, and low-stakes products don&apos;t get bought by buyers with real budget authority.</p><p>The correction is to price for the position you want, and let the positioning catch up to the number. If the plan is to sell to enterprise, an SMB price contradicts the plan on contact.</p><p>The number itself is a positioning claim, and underpricing is a way of telling the market you don&apos;t believe what your own homepage says.</p><h2 id="hiring-is-downstream-of-narrative"><strong>Hiring is downstream of narrative</strong></h2><p>People want to work for companies whose story they can repeat at a dinner party without sounding ridiculous. If your narrative is sharp, you can hire above your weight class. If it&apos;s muddy, every hire becomes a war.</p><p>I&apos;ve watched companies with worse products win senior hires from companies with better products, because the narrative was clearer and the candidates could picture themselves inside it. The folks who are actually in demand evaluate the story before the feature set. They want to know whether the story they&apos;ll tell their next employer about this job will sound impressive or embarrassing. We&#x2019;re all climbing the ladder. Your story has to place you one rung up.</p><p>The same logic applies to retention. The best people leave when they can no longer explain what the company is doing. They leave before the bad ones do, because the bad ones don&apos;t have other options, and the good ones run the calculation every six months.</p><p>A clear positioning is a retention tool. It tells your best engineers why their work matters at the scale of the company, and it lets them say something coherent at parties when someone asks where they work.</p><h2 id="when-to-reposition"><strong>When to reposition</strong></h2><p>Repositioning is the most dangerous play in the manual. Done well, it can rescue a stalled company in a quarter; done badly, it can torch ten years of accumulated meaning in a week.</p><p>A company should reposition when one of four things happens.</p><ol><li>The market has moved underneath the original claim, and the position now describes a world that no longer exists.</li><li>The product has expanded into territory the original claim can&apos;t cover, and customers are confused about what they&apos;re actually buying.</li><li>A competitor has captured the language you used to own, and the contrast has stopped doing the work it used to do. Or,</li><li>the founders have learned something material about who their best customers are, and the original audience description has stopped matching the people writing the cheques.</li></ol><p>Repositioning that happens because the founders are bored with their own message will always fail; personal boredom is not a strategic signal. The customer hasn&apos;t heard the message yet. The customer is just starting to remember it. Throwing it out because the founders have repeated it a thousand times is throwing out the only thing the market has begun to recognise.</p><p>Most repositioning attempts try to rewrite everything, and most fail because the new version has no equity, no recognition, and no proof points. A surgical change at the wedge or the alternative is easier to absorb than a full rebrand of the category and audience.</p><h2 id="founders-as-narrators"><strong>Founders as narrators</strong></h2><p>Every founder is the chief narrator of the company, whether they want the role or not. Investors read founders; hires read founders; and customers read founders. The way the founders talk about the company in informal settings tells the market more than any campaign ever will.</p><p>The founders who win at this discipline share two habits.</p><ol><li>They use the same vocabulary to describe the company across every audience, so the deck, the all-hands speech, the analyst briefing, and the dinner-table answer to a stranger all sound like they came from the same head.</li><li>They resist the temptation to update the story every time a journalist asks a clever question, because they understand that the question is a test of conviction, not an invitation to redesign the company in real time.</li></ol><p>Founders who lose at this discipline tend to do the opposite. They tailor the story to whoever&apos;s in the room. The deck says one thing, the all-hands says another, the analyst briefing says a third, and the dinner-table answer says a fourth. Over time the company loses the ability to say anything at all, because nobody inside it can agree on what the company is.</p><p>The fix is the spine again. Write it down, read it out loud, and use the words themselves. The discipline is to bore yourself with your own message a decade before the market starts repeating it back, and to keep saying the same true thing while competitors burn their oxygen on rebrands every eighteen months.</p><h2 id="what-to-do-this-week"><strong>What to do this week</strong></h2><p>Skip the rebrand for now. Sit five people in a room and finish the sentence: &quot;We are the _____ for _____ who want to _____ instead of _____.&quot;</p><p>The blanks are the spine: category, audience, outcome, alternative.</p><p>If everyone in the room agrees on the completed sentence, the company has working positioning. If the sentence doesn&apos;t read cleanly to everyone, no amount of homepage redesign or paid advertising will fix the underlying problem, because the underlying problem is that the company doesn&apos;t know what it is.</p><p>Run the exercise this week. Don&apos;t leave the room until the sentence reads cleanly. Then check it against the homepage, the deck, the sales script, and the latest job posting. Anything that contradicts the sentence is a leak in the spine. Patch the leaks one by one, and don&apos;t open a new marketing channel until they&apos;re closed.</p><h2 id="the-longer-game"><strong>The longer game</strong></h2><p>Positioning is a posture you hold for years, not a campaign you run for a quarter. Companies that hold a clear posture for a decade compound advantages that companies running a fresh campaign every quarter never accumulate.</p><p>Berkshire Hathaway&apos;s annual letter has said the same things, with the same vocabulary, since the 1970s. Buy good businesses at fair prices, hold them forever, trust the underlying math, and ignore the short-term noise. The letter doesn&apos;t change because the position doesn&apos;t change. The position doesn&apos;t change because Warren Buffett worked out what he believed early and refused to negotiate with the market about it.</p><p>You don&#x2019;t have fifty years. At most, at the absolute stretch, you have 2-3 before the company either compounds into something or doesn&apos;t.</p><p>Pick the claim, hold the claim, write everything else from the claim, and let competitors burn their oxygen on rebrands every eighteen months while you keep saying the same, damned, true ~thing.</p> Announcing Wonders of Web Weaving - James' Coffee Blog https://jamesg.blog/2026/05/12/announcing-wonders-of-web-weaving 2026-05-12T00:00:00.000Z <p>If you have ever spoken to me, you may have heard me express a meandering interest in doing something with audio. I think the heart of this interest is that I love conversations and storytelling. I love hearing people talk about the things that make them light up. I love asking questions. I enjoy the feeling where you feel like you see the world in a new light after having spoken with someone.</p><p>With all that in mind, a few weeks ago I had an idea: I could interview people who love the web and chat about all things indie web. This coalesced into an outline for a podcast, which then became <a href="https://web-weaving.jamesg.blog/">Wonders of Web Weaving</a>.</p><p>Every Tuesday for the next fifteen or so weeks, I am going to be releasing an episode of the show. <a href="https://web-weaving.jamesg.blog/1/">The first episode is with Adam, the creator of omg.lol and maintainer of many wonderful web projects</a>.</p><p>I named the podcast the way I did because web weaving – making websites and the community around doing making websites – really is wonderful. After the first interview, I felt I had made the right choice in the name – the magic of the web permeates through so much of the indie web.</p><p>The show has its own website, which has an <a href="https://web-weaving.jamesg.blog/subscribe/" rel="noreferrer">RSS feed you can use to follow along with episodes</a>. Each episode will be accompanied by a hand-written transcription, available on the web page for each episode.</p><p>I am thinking of the next fifteen weeks as either season one, or the entirety of the show. Whether there will be another season, I’m not sure. For now, I’m challenging myself to commit to fifteen conversations. Having a clear goal towards which I can strive makes the project more sustainable than committing to a recurring show.</p><p>I hope that you all enjoy the show as much as I enjoy recording it. <a href="https://web-weaving.jamesg.blog/1/">The first episode is ready for you.</a></p><script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9fa7f77ada89d230',t:'MTc3ODU3MzYzMw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&amp;&amp;(document.onreadystatechange=e,c())}}}})();</script> <a class="tag" href="https://web-weaving.jamesg.blog/">Wonders of Web Weaving</a> <a class="tag" href="https://web-weaving.jamesg.blog/1/">The first episode is ready for you.</a> <a class="tag" href="https://web-weaving.jamesg.blog/1/">The first episode is with Adam, the creator of omg.lol and maintainer of many wonderful web projects</a> <a class="tag" href="https://web-weaving.jamesg.blog/subscribe/">RSS feed you can use to follow along with episodes</a> Bridging feels seamless. Behind the scenes, it's a technical marvel - Werd I/O 6a02585fe66c4000011e2a37 2026-05-11T22:29:51.000Z <p>Link: <a href="https://blog.anew.social/bridging-on-a-budget/?ref=a-new-social-newsletter"><em>Bridging on a budget, by Ryan Barrett at A New Social</em></a></p><p>I&#x2019;ve been in awe of <a href="https://snarfed.org/?ref=werd.io">Ryan Barrett</a> since I first met him over a decade ago. He cofounded <a href="https://cloud.google.com/appengine?ref=werd.io">Google App Engine</a> and led engineering at <a href="https://www.color.com/?ref=werd.io">Color Health</a>. His <a href="https://fed.brid.gy/?ref=werd.io">Bridgy</a> tool, which allows people on different protocols and networks to follow and converse with each other, is now the basis of <a href="https://anew.social/?ref=werd.io">A New Social</a>, the open social web non-profit that he runs with <a href="https://augment.ink/?ref=werd.io">Anuj Ahooja</a>. (Disclosure: I&#x2019;m on the board.)</p><p>This post about how he reduced Bridgy costs is brilliantly detailed. It&#x2019;s a good look into what&#x2019;s involved when you need to refactor and reduce cost at scale &#x2014; and what&#x2019;s remarkable is how effective this work actually was.</p><blockquote>&#x201C;The end result of all of this is that we grew from 2k users to almost 150k, added a ton of heavy new functionality, and still managed to optimize and cut down costs from $.15 per active user per month to just $.03 or so.&#x201D;</blockquote><p>But it didn&#x2019;t come easily. When you&#x2019;re connected to the kinds of firehoses that Bridgy needs to be, and serving the kind of traffic it&#x2019;s starting to handle, every optimization really counts. Because it&#x2019;s open-source, you can <a href="https://github.com/snarfed/arroba/issues/88?ref=werd.io">dig down into individual optimizations</a> and follow along each exploration. It&#x2019;s painstaking work and a demonstration of their commitment to financial responsibility. Try vibe coding <em>that</em>.</p><p>Bridgy (and its parent A New Social) exists to help make the individual protocols less important: everyone should be able to collaborate with everyone else regardless of which platform they&#x2019;re using. It&#x2019;s the kind of thing that feels easy in the moment &#x2014; but as this post proves, it&#x2019;s far from simple under the hood.</p> To maintain their independence, publishers are fleeing Substack - Werd I/O 6a025101e66c4000011e2a31 2026-05-11T21:58:25.000Z <p>Link: <a href="https://www.theverge.com/tech/927294/substack-tax-ghost-beehiiv?ref=werd.io"><em>Writers are fleeing the Substack Tax, by Emma Roth in The Verge</em></a></p><p>If you weren&#x2019;t all that bothered about Substack platforming and compensating Nazis, <em>The Verge</em> reports that there&#x2019;s a new reason to be worried: it costs more and its much-touted network doesn&#x2019;t count for much if you&#x2019;re not one of its featured writers.</p><p>Sean Highkin of <em>The Rose Garden Report</em> is quoted in the piece:</p><blockquote>&#x201C;&#x201C;When I first joined up, [Substack] gave me a big push and featured me and funneled a lot of traffic to me, which led to a good amount of growth,&#x201D; Highkin says. &#x201C;But once I wasn&#x2019;t one of the &#x2018;new recruited talent&#x2019; they could tout, they stopped featuring me and I saw my growth stagnate.&#x201D;&#x201D;</blockquote><p><a href="https://ghost.org/?ref=werd.io">Ghost</a> (with Ryan Singel&#x2019;s <a href="https://outpost.pub/?ref=werd.io">Outpost</a>) cost less than half and drove a significant increase in subscribers. It&#x2019;s mentioned here alongside Beehiiv and Kit, but is the only truly open-source alternative. That means you <em>can</em> use Ghost&#x2019;s services (as I do), but if you&#x2019;re dissatisfied, you can move to another provider.</p><p>This is in stark contrast with Substack, which has been promoting social media style following relationships over true subscriptions, and only allows creators to export their subscribers should they choose to move. Similarly, Beehiiv starts with open protocols like RSS switched off by default, locking readers into its ecosystem.</p><p>That freedom is important. As <a href="https://www.platformer.news/?ref=werd.io">Casey Newton</a> says in the piece:</p><blockquote>&#x201C;The more important thing is that we have a home on the open web that we control, and whatever anti-creator changes Substack is forced to make in the future to live up to its valuation we won&#x2019;t be affected by.&#x201D;</blockquote><p>Every media company, publisher, and individual creator needs to maintain their platform independence if they want to make independent business decisions. It&#x2019;s good to see more people taking this step, and it&#x2019;s good to see that they have options.</p> Asking platforms to do better won't work. We need to force their hands - Werd I/O 6a01e857e66c4000011e2a01 2026-05-11T14:31:51.000Z <p>Link: <a href="https://mattdpearce.substack.com/p/you-couldnt-create-a-more-anti-news?publication_id=2382711&amp;utm_campaign=email-post-title&amp;r=a98j&amp;utm_medium=email&amp;ref=werd.io"><em>You couldn&apos;t create a more anti-news internet if you tried, by Matt Pearce</em></a></p><p>Matt Pearce, Director of Policy for Rebuild Local News, writes a behavioral economics inspired take on why our current embodiment of the internet is so bad for news and information.</p><p>In particular, he sees the introduction of &#x201C;nudges&#x201D; as being a pro-information feature that search engines, LLM interfaces, and social media platforms could introduce:</p><blockquote>&#x201C;Social media, too, could choose to feature quality news outlets as &#x201C;defaults&#x201D; or provide subtle &#x201C;nudges&#x201D; on content that prompt users to donate or subscribe to the news outlets providing high quality news videos on platforms like Instagram, which don&#x2019;t pay for themselves.&#x201D;</blockquote><p>I happen to particularly agree with his implied criticism of newsrooms going deep on Instagram, which usually leads to vanity metrics going up and to the right but not necessarily to conversions, impact, or revenue. And I think it&#x2019;s true that nudges across all these platforms would have the effect he&#x2019;s hoping for. But I think the tragedy is that there&#x2019;s no real reason why any of these platforms would actually do it.</p><p>The internet as it stands is perfectly optimized for the needs of these platforms: engagement, advertising revenue, and rapid growth. Adding pro-social nudges would add friction to their well-oiled loops and take users off-platform. That&#x2019;s exactly why Google has moved from leading people to the best websites for a query to answering those questions on-page: its own needs are best served by keeping users in one place. For them to make different choices, they would need to be far more benevolent architects than they are.</p><p>So, one path forward is that they need to be <em>forced</em> to do it. This would need regulations to govern the features an information platform can provide, and could have very adverse side effects. We&#x2019;re seeing increased regulations with respect to things like age verification, so introducing regulation is possible &#x2014; but that age verification tech has become a surveillance layer that impacts freedom of speech for vulnerable groups. And if publishers go too far in that direction, for example by dictating that platforms share more ad revenue, the networks might simply stop supporting news content at all, <a href="https://www.cbc.ca/news/politics/online-news-act-meta-facebook-1.6885634?ref=werd.io">as we&#x2019;ve seen in places like Canada</a>.</p><p>Another is to build new platforms that make better choices for the whole ecosystem: more interesting for readers, more supportive of publishers. We&#x2019;re already seeing a resurgence in new open social web platforms as well as a regrowth in older technologies like RSS. But the incumbent platforms aren&#x2019;t going to simply go away; any new pro-social platform has to directly compete with them while also building an ecosystem. Still, I think it&#x2019;s more promising, particularly in a world where incumbent platforms are losing goodwill with the public. The kind of thinking that Matt&#x2019;s done here is very useful in helping to design what those new platforms might look like.</p><p>We&#x2019;re not in a great place and there&#x2019;s a hard road ahead. I&#x2019;m sure of one thing: asking existing platforms to do better is not going to work. So we need to take matters into our own hands.</p> WordPress powers 47% of the web. Now it's more social, too - Werd I/O 6a01da49e66c4000011e29f5 2026-05-11T13:31:54.000Z <p>Link: <a href="https://activitypub.blog/2026/05/05/radical-speed-month-the-reader-meets-the-fediverse/?ref=werd.io"><em>Radical Speed Month &#x2014; The Reader Meets the Fediverse, by Mattias Pfefferle</em></a></p><p>We&#x2019;re closer to the entire web being a social environment than ever before. That&#x2019;s very exciting to me on two fronts. The first is that it&#x2019;s always been the promise of the web that anyone could publish and be heard, and baking in social functionality is a huge part of that. The second is that it undermines the stranglehold that traditional social media platforms have had on the public discourse and democracy itself. We need movements like these to grow.</p><p>So I think it&#x2019;s cool that WordPress.com just shipped some major improvements to its core reader:</p><blockquote>&#x201C;The Radical Speed Month bet: ship three protocol adapters in four weeks, and prove the Reader can become a universal aggregator. RSS / Google Reader API (so any reader app can use WordPress.com as a sync backend), ActivityPub (so Mastodon, Pixelfed, and friends show up natively), and ATProto / Bluesky (because that&#x2019;s where a real chunk of the social-web conversation has gone). One Reader, every protocol you care about.&#x201D;</blockquote><p>In practice, that means that you can read updated content from the web via RSS, the Fediverse, and ATproto from the WordPress dashboard &#x2014; and connect any compatible reader app to that dashboard to make reading more seamless. (I&#x2019;m a die-hard fan of <a href="https://reederapp.com/classic/?ref=werd.io">Reeder Classic</a>, and it sounds like that works.) WordPress is now compatible with <em>reading</em> the whole open social web.</p><p>But, of course, it&#x2019;s WordPress, which is a publishing environment at its heart. It&#x2019;s supported RSS forever, and has supported the Fediverse for a while. Now it supports Bluesky, too. Unlike most readers, which are read-only environments, you can interact with those sources right from your feed, including by publishing posts and replying to other people&#x2019;s.</p><p>That&#x2019;s something the <a href="https://indieweb.org/?ref=werd.io">indie web</a> community has been thinking about forever: people like Aaron Parecki have been <a href="https://aaronparecki.com/2018/04/20/46/indieweb-reader-my-new-home-on-the-internet?ref=werd.io">building their own interactive readers</a> using open web standards, and I remember working on a simple prototype at an IndieWebCamp in Portland.</p><p>But it&#x2019;s also an idea that has become more powerful as the open social web has grown. There are millions of people to interact with &#x2013; all of whom might be publishing from their own websites, on their terms, free from intermediation. May it continue to grow and spread.</p> Find blog posts with missing featured images - and missing alt text - without a plugin - Terence Eden’s Blog https://shkspr.mobi/blog/?p=63594 2026-05-11T11:34:39.000Z <p>WordPress has the concept of "Featured Images". They are the images which show up when you share a blog post on social media or, on some themes, as the "hero" image.</p> <p>How can you quickly and easily find any posts which <em>don't</em> have a featured image?</p> <p>For this, I use <a href="https://wp-cli.org/">WP CLI</a> - it allows you to run complex WordPress actions and queries using the command line. After you have <a href="https://wp-cli.org/#installing">installed WP CLI</a> you can get started.</p> <h2 id="missing-images"><a href="https://shkspr.mobi/blog/2026/05/find-blog-posts-with-missing-featured-images-and-missing-alt-text-without-a-plugin/#missing-images">Missing Images</a></h2> <p>On the command line, run:</p> <pre><code class="language-_">wp eval 'foreach(get_posts(array("post_type"=&gt;"post","post_status"=&gt;array("publish"),"posts_per_page"=&gt;-1,)) as $post){if(get_the_post_thumbnail($post)==""){$post_type_object=get_post_type_object($post-&gt;post_type);$link=admin_url(sprintf($post_type_object-&gt;_edit_link . "&amp;action=edit", $post-&gt;ID));echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n";}}' </code></pre> <p>Here's the code in a slightly more readable format:</p> <pre><code class="language-php">foreach ( get_posts( array( "post_type" =&gt; "post", "post_status" =&gt; array("publish"), "posts_per_page" =&gt; -1, ) ) as $post) { if( get_the_post_thumbnail( $post)== "" ) { $post_type_object = get_post_type_object( $post-&gt;post_type ); $link = admin_url( sprintf( $post_type_object-&gt;_edit_link . "&amp;action=edit", $post-&gt;ID ) ) ; echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n"; } } </code></pre> <p>That will print out:</p> <pre><code class="language-_">2024-05-02 12:34:11 https://example.com/wp-admin/post.php?post=123&amp;action=edit "A post about sausages" 2023-09-13 20:55:52 https://example.com/wp-admin/post.php?post=456&amp;action=edit "I like cheese" 2021-12-31 15:43:33 https://example.com/wp-admin/post.php?post=789&amp;action=edit "Touching computers" </code></pre> <p>You can then go and edit each of those posts to add a featured image.</p> <h2 id="missing-alt-text"><a href="https://shkspr.mobi/blog/2026/05/find-blog-posts-with-missing-featured-images-and-missing-alt-text-without-a-plugin/#missing-alt-text">Missing Alt Text</a></h2> <p>Adding alt text means that people who can't see images will still be able to understand what the picture represents. Here's another one-lines to find all featured images with missing alt text:</p> <pre><code class="language-_">wp eval 'foreach (get_posts(array("post_type"=&gt;"post","post_status"=&gt;array("publish"),"posts_per_page" =&gt; -1,)) as $post){if(simplexml_load_string(get_the_post_thumbnail($post))["alt"]==""){$post_type_object=get_post_type_object($post-&gt;post_type);$link=admin_url(sprintf($post_type_object-&gt;_edit_link . "&amp;action=edit",$post-&gt;ID));echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n";}}' </code></pre> <p>And, in slightly more readable form:</p> <pre><code class="language-php">foreach ( get_posts( array( "post_type" =&gt; "post", "post_status" =&gt; array("publish"), "posts_per_page" =&gt; -1, ) ) as $post) { if( simplexml_load_string( get_the_post_thumbnail( $post ) )["alt"] == "") { $post_type_object = get_post_type_object( $post-&gt;post_type ); $link = admin_url( sprintf( $post_type_object-&gt;_edit_link . "&amp;action=edit", $post-&gt;ID ) ) ; echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n"; } } </code></pre> <p>Again, that lists the datetime of the post, its edit link, and its title.</p> <p>No, if you'll excuse me, I have about 873 posts which need updating 🤯</p> <img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=63594&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager"> Hey you, start communicating! - Kev Quirk https://kevquirk.com/hey-you-start-communicating 2026-05-11T08:25:00.000Z <div class="link card"><h2>Hey you, start communicating!</h2><p class="post-author">by David Jamieson</p><p>David talks about why it's good to reach out to authors when you read their content. Even if it's just to say hi.</p><p><a class="button" target="_blank" href="https://forkingmad.blog/hey-you-start-communicating/">Read post ➡</a></p></div><p>Hard agree with David's comments here - he and I regularly exchange emails, actually. I try to reach out to authors whenever I read something that resonates with me. I'll also try to share their work via posts like this too.</p> <p>For me, blogging is the original social network; just because we're on our own spaces doesn't mean we can't be socially connected. That's why I offer comments, and a reply by email link on all posts, including my RSS feed.</p> <p>So yeah, start communicating! 🙃</p> <div class="email-hidden"> <hr /> <p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p> <p>You can <a href="mailto:19gy@qrk.one?subject=Hey%20you%2C%20start%20communicating%21">reply to this post by email</a>, or <a href="https://kevquirk.com/hey-you-start-communicating#comments">leave a comment</a>.</p> </div> Fear is information. - Westenberg 6a0137c865b5c30001913096 2026-05-11T03:52:45.000Z <img src="https://www.joanwestenberg.com/content/images/2026/05/photo-1568494944313-e93378ba98dd.jpeg" alt="Fear is information."><p>The motivational industry has built any number of small empires on the notion that fear is a problem to be either managed, suppressed or out-manoeuvred. Fight the fear, etc. The language is typically martial - as if fear were a hostile enemy, camped at the gates of your better self.</p><p>But this is sloppy thinking that comes at a cost.</p><p>When the body floods with adrenaline // the mind locks onto a single threat, the system is doing what it evolved to do: reporting on the state of whatever it is you care about. The signal bypasses the conscious mind almost entirely; which is why you can spend years lying to yourself about what you want and still flinch at the wrong moment when the thing you value comes under threat.</p><p>My basic claim is this. When someone (anyone, everyone) is afraid, they&apos;re telling you what they actually value. Their fear is a noisy, but no less precise indicator of both the surface threat and their underlying stake. A founder who keeps delaying their launch has a private worry that has almost nothing to do with the launch itself; they&apos;re deathly afraid of the dissonance between who they&apos;ve been telling people (and themselves) they are and who the market will reveal them to be. The surface object of the fear is misdirection; the actual content is a value statement signed in the writer&apos;s own hand.</p><p>You can argue with the rationalisations that get layered on top of the stake, but you can&apos;t argue with the signal itself.</p><p>People will lie to you about what they want, and they&apos;ll lie to themselves with even greater conviction. But their fear won&apos;t lie, because it can&apos;t. It&apos;s older than language and it runs on a circuit that doesn&apos;t consult the part of the mind responsible for maintaining a neat // tidy story.</p><p>If you want to know what someone actually values, pay attention to what they protect.</p><p>A client who keeps fixating on the timeline is afraid of something other than the difference between three weeks and four. Their fear is tied to a board meeting, or a budget cycle, or personal pressure. A prospect who keeps circling back to price is using the price as a placeholder for a deeper fear about whether they&apos;ll be able to defend their decision if it all goes sideways.</p><p>If you read the fear correctly, you can stop arguing with the placeholder and start addressing the actual stake.</p><p>Your own fear works in much the same way; it&apos;s drawn from a part of you that doesn&apos;t bother with self-deception. When you flinch at sending an email, you&apos;re exporting data about that relationship. When a project keeps slipping in your calendar - whether or not you&apos;ve admitted to deprioritising it - your behaviour is an indicator. The thought of having that one conversation you&apos;ve been putting off makes your stomach turn because you&apos;re responding to a real assessment of the stakes that the &quot;refined&quot; part of your brain has refused to acknowledge.</p><p>I&apos;ve caught myself avoiding decisions for weeks at a time, generating elaborate justifications for the delay, when the actual reason was a single, one-line fear I would&apos;ve been utterly embarrassed to say out loud.</p><p>But the fear is almost always right.</p><p>Even if it&apos;s usually wrong about what to do with the information&#x2026;</p><p>Fear is excellent intelligence, but it&apos;s not much of a strategy. It tells you what&apos;s at risk with high fidelity, and what to do about that risk with all the sophistication of a small mammal in a patch of tall grass; the amygdala, after all, rarely understands either long games or leverage. If you let the part of you that knows what&apos;s at stake dictate your response to that stake, you&apos;ll spend your life flinching away from the things that matter to you and into the things that look superficially safer.</p><p>This is why so much of the advice we give // receive about fear is suspicious of the concept without quite understanding why. People do get controlled by their fear, and that control does produce bad outcomes; but it&apos;s a mistake to conclude that fear is therefore a corrupting influence and that it has to be smothered. The fear is fine - useful, even. The problem is letting an instrument designed for tactical reflexes write the plan.</p><p>Acknowledge the fear and read it carefully; and refuse to be moved by it until you&apos;ve understood what it&apos;s telling you.</p><p>Then decide whether the information changes the plan.</p><p>But stop treating fear as either a master or an enemy. It&apos;s an instrument, and like any instrument, you have to read it and you have to choose what to do with the data it offers.</p><p>The list of things you&apos;re afraid to lose is the most accurate map you have of whatever you&apos;ve built your life around. If you want to know what actually matters to you, watch what your nervous system does when something&#x2019;s threatened. The list might not match the vision document you&apos;d recite on a podcast, but it&apos;s much closer to a source of truth.</p><p>I find that clarifying rather than depressing. </p><p>The world is not as opaque as the official explanations make it look. People are constantly broadcasting what they value, in a frequency older than speech, on a channel they can&apos;t turn off. You only have to learn to listen to it, and be willing to listen to yourself. </p><p>The discipline is the same in both directions; read the signal carefully, and then decide what to do with the information, free of any pressure to obey it.</p>