Shellsharks Blogroll - BlogFlock2026-05-16T18:18:19.422ZBlogFlockAdepts of 0xCC, destructured, fLaMEd, Aaron Parecki, Trail of Bits Blog, gynvael.coldwind//vx.log (pl), James' Coffee Blog, Westenberg, joelchrono, Evan Boehs, Kev Quirk, cool-as-heck, 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 BlogA quarter of a century of open educational technology - Werd I/O6a089b814154ba0001030ad32026-05-16T16:29:53.000Z<p>Link: <a href="https://halfanhour.blogspot.com/2026/05/25-years-of-oldaily.html?ref=werd.io"><em>25 Years of OLDaily, by Stephen Downes</em></a></p><p>If you’re not in educational technology, it’s possible you might not know who Stephen Downes is. If you are, there’s no way you don’t. For a quarter century now, his daily updates at <a href="https://www.downes.ca/news/OLDaily.htm?ref=werd.io">OLDaily</a> have been one of the main ways people learn about the space; part reporter, part advocate, he’s pushed for an open web approach to education that’s been genuinely influential. And all on one of the very first ling blogs.</p><p>My own work on Elgg, which kickstarted my career, was directly inspired <a href="https://www.downes.ca/post/7528?ref=werd.io">by a post Stephen made about a white paper Dave Tosh and I had written</a> about social spaces for learning, 22 years ago:</p><blockquote>“[…] The authors' proposal is visionary. "Creation of a learning landscape where learners engage in the whole process both academically and socially should increase the opportunity to build one's learning instead of just being the recipients of information." If your view of portfolios is just something akin to a content management system, don't bother. But if it's the student's personal and continuing presence in an online community of discourse, then you are on to something.”</blockquote><p>Twenty five years of this is an incredible achievement — clearly he touched my life, but I’m certain I’m not alone.</p><p>As Stephen says:</p><blockquote>“Though nothing I have ever written has been as popular as that first Guide to the Logical Fallacies (I could probably have built a career off it), I think that OLDaily has been my most substantial contribution, not the least because it wasn't about me and my accomplishments, but about the wider community that made everything possible. My story really is our story, my history really is our history.”</blockquote><p>For open educational technology, there has been no more diligent and influential chronicler.</p>Is Bitwarden preparing for a sale? - Kev Quirkhttps://kevquirk.com/is-bitwarden-preparing-for-a-sale2026-05-16T12:06:00.000Z<div class="link card"><h2>Is Bitwarden preparing for a sale?</h2><p class="post-author">by Jan-Lukas Else</p><p>Jan-Lukas writes about the warning signs that Bitwarden might be heading for a private equity sale. The irony is that founder built Bitwarden because he didn't trust what happened when LastPass got acquired.</p><p><a class="button" target="_blank" href="https://janlukas.blog/links/2026/05/bitwarden-sale">Read post ➡</a></p></div><p>I saw this on the fedi this morning and it made me let out a big sigh. I was an early adopter of Bitwarden, having used it for nearly 10 years at this point, after <a href="https://kevquirk.com/lastpass-joins-logmein-what-now">LastPass were acquired by LogMeIn</a>.</p>
<p>If this does come to fruition (I <em>really</em> hope it doesn't) I'm not sure what I'd do. My wife and I have a family account and share many credentials, so whatever I potentially flip to would need to be super simple to use, like Bitwarden.</p>
<p>The fact that Bitwarden is so simple yo use, <a href="https://bitwarden.com/help/is-bitwarden-audited/">yet so secure</a>, is a testament to how good of a product it really is. So I'd rather not jump ship.</p>
<h2>Let's not get ahead of ourselves</h2>
<p>In the <a href="https://www.fastcompany.com/91542655/bitwarden-scrubs-always-free-and-inclusion-values-from-its-website-as-longtime-execs-step-down">Fast Company post</a> that Jan-Lukas links to, there's a quote following an email from Bitwarden's "chief customer officer", Gary Orenstein, saying:</p>
<blockquote>
<p>Orenstein says via email that Bitwarden is not seeking a buyer, and that Sullivan’s [new CEO] appointment “reflects a continued focus at Bitwarden on scaling the business and serving customers globally.”</p>
</blockquote>
<p>That gives me some hope, but it could also be corporate bullshit - let's be honest, it wouldn't be the first time.</p>
<p>I'm not going to make any rash decisions though. I get a tonne of use from Bitwarden, so I don't want to move unless I have to. Even if they are sold, I'd have to consider my options once I know who they've <em>potentially</em> been sold to.</p>
<p>For now it's business as usual for me and my password manager.</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=Is%20Bitwarden%20preparing%20for%20a%20sale%3F">reply to this post by email</a>, or <a href="https://kevquirk.com/is-bitwarden-preparing-for-a-sale#comments">leave a comment</a>.</p>
</div>Think small: achieve something / Think big: probably fail - Johnny.Decimalhttps://johnnydecimal.com/blog/0197-castle-hill-website/2026-05-16T09:19:44.000Z<p>Some time around 1998 I mentioned to my girlfriend's mam, then headmistress at the local infant school, that I could probably make her a website. I had a knock-off copy of <a href="https://en.wikipedia.org/wiki/Adobe_Dreamweaver">Dreamweaver</a> that I barely understood, so off I went.</p>
<p>The problem is one I've come to recognise in myself in the intervening 30 years: thinking <em>way</em> too big. What did she want from this website, which would have been one of perhaps a dozen UK infant school websites in 1998, had it ever existed? She'd have been happy with a handful of pages with a couple of images.</p>
<p>Had I created a handful of pages I could see a future where I got a small contract with Suffolk County Council, slowly learned my trade, and spent the 2000s making a fortune as an independent web developer.</p>
<p>Unfortunately, I had Dreamweaver. Dazzled by this technology, I tried to develop something <em>way</em> beyond my skills. I remember trying to work out some sort of fancy breadcrumb solution. 1998, remember. The internet existed but there was nothing on it. Nobody to tell me what to do.</p>
<h2 id="so-i-just-gave-up">So I just gave up</h2>
<p>That's what I did. I just … stopped. There was never a website. I don't even remembering telling her that I couldn't do it, it just fizzled out.</p>
<p><strong>Start small</strong>. Small is achievable. Just do some minimal version. Make <em>a thing</em> that works. Make it good – I'm not saying churn out rubbish – but make it <em>minimal</em>. Now, did people like it? Did you enjoy making it? Okay, now learn a bit more and make it better. And now keep doing that.</p>Notable links: May 15, 2026 - Werd I/O6a07db544154ba00010306c32026-05-16T02:56:44.000Z<img src="https://images.unsplash.com/photo-1588681664899-f142ff2dc9b1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDJ8fG5ld3NmZWVkfGVufDB8fHx8MTc3ODkwMDE3Mnww&ixlib=rb-4.1.0&q=80&w=2000" alt="Notable links: May 15, 2026"><p><em>Most Fridays, I share a handful of pieces that caught my eye at the intersection of technology, media, and society.</em></p><p><em>Did I miss something important? </em><a href="mailto:ben@werd.io" rel="noreferrer"><em>Send me an email</em></a><em> to let me know.</em></p><hr><h3 id="after-the-feed"><a href="https://newpublic.org/afterthefeed?ref=werd.io" rel="noreferrer">After the Feed</a></h3><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 — AI adoption curves, data about social media use, qualitative evidence about how people are using AI to gather information today — point to the fact that it will.</p><p>This is the crux:</p><blockquote>“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 — 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.”</blockquote><p>For me, the framing of AI’s effects on existing information ecosystems while it establishes a new one was helpful. It’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 “<em>new</em> new gatekeepers”. 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’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’m biased towards New_ Public’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’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’m grateful for this encapsulated research, which I think will help to guide us all.</p><hr><h3 id="writers-are-fleeing-the-substack-tax"><a href="https://www.theverge.com/tech/927294/substack-tax-ghost-beehiiv?ref=werd.io" rel="noreferrer">Writers are fleeing the Substack Tax</a></h3><p>If you weren’t all that bothered about Substack platforming and compensating Nazis, <em>The Verge</em> reports that there’s a new reason to be worried: it costs more and its much-touted network doesn’t count for much if you’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>““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,” Highkin says. “But once I wasn’t one of the ‘new recruited talent’ they could tout, they stopped featuring me and I saw my growth stagnate.””</blockquote><p><a href="https://ghost.org/?ref=werd.io">Ghost</a> (with Ryan Singel’s <a href="https://outpost.pub/?ref=werd.io">Outpost</a>) cost less than half and drove a significant increase in subscribers. It’s mentioned here alongside Beehiiv and Kit, but is the only truly open-source alternative. That means you <em>can</em> use Ghost’s services (as I do), but if you’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>“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’t be affected by.”</blockquote><p>Every media company, publisher, and individual creator needs to maintain their platform independence if they want to make independent business decisions. It’s good to see more people taking this step, and it’s good to see that they have options.</p><hr><h3 id="radical-speed-month-%E2%80%94-the-reader-meets-the-fediverse"><a href="https://activitypub.blog/2026/05/05/radical-speed-month-the-reader-meets-the-fediverse/?ref=werd.io" rel="noreferrer">Radical Speed Month — The Reader Meets the Fediverse</a></h3><p>We’re closer to the entire web being a social environment than ever before. That’s very exciting to me on two fronts. The first is that it’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’s cool that WordPress.com just shipped some major improvements to its core reader:</p><blockquote>“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’s where a real chunk of the social-web conversation has gone). One Reader, every protocol you care about.”</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 — and connect any compatible reader app to that dashboard to make reading more seamless. (I’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’s WordPress, which is a publishing environment at its heart. It’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’s.</p><p>That’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’s also an idea that has become more powerful as the open social web has grown. There are millions of people to interact with – all of whom might be publishing from their own websites, on their terms, free from intermediation. May it continue to grow and spread.</p><hr><h3 id="the-first-year"><a href="https://pointc.co/the-first-year/?ref=the-idea-bucket-newsletter" rel="noreferrer">The First Year</a></h3><p>I could include Corey Ford’s posts in my <a href="https://werd.io/tag/links">link roundups</a> every single week. Each one is genuinely gold — and I’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’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’ve been blogging since 1998 and I’m not convinced I’ve <em>ever</em> been that consistent. As he says, consistency compounds:</p><blockquote>“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'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.”</blockquote><p>I’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’ve been in board meetings at other orgs where his work has come up organically and I’ve been able to enthusiastically +1. If you’re not following him, there’s still time to correct that. He’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> — run at it.</p><hr><h3 id="bridging-on-a-budget"><a href="https://blog.anew.social/bridging-on-a-budget/?ref=a-new-social-newsletter" rel="noreferrer">Bridging on a Budget</a></h3><p>I’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’m on the board.)</p><p>This post about how he reduced Bridgy costs is brilliantly detailed. It’s a good look into what’s involved when you need to refactor and reduce cost at scale — and what’s remarkable is how effective this work actually was.</p><blockquote>“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.”</blockquote><p>But it didn’t come easily. When you’re connected to the kinds of firehoses that Bridgy needs to be, and serving the kind of traffic it’s starting to handle, every optimization really counts. Because it’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’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’re using. It’s the kind of thing that feels easy in the moment — but as this post proves, it’s far from simple under the hood.</p><hr><h3 id="the-biggest-student-data-privacy-disaster-in-history-canvas-hack-shows-the-danger-of-centralized-edtech"><a href="https://www.404media.co/the-biggest-student-data-privacy-disaster-in-history-canvas-hack-shows-the-danger-of-centralized-edtech/?ref=werd.io" rel="noreferrer">'The Biggest Student Data Privacy Disaster in History': Canvas Hack Shows the Danger of Centralized EdTech</a></h3><p>I started in edtech. When I graduated with my Computer Science degree, I returned to the university to work at the Media and Learning Technology Service. There, I discovered that all the edtech software at the time was <em>so bad</em> — the learners hated it, the teachers hated it, the administrators hated it, and I have to assume the people who made it also had a deep-seated contempt for it — that it actively made learning worse. Worse, these platforms were charging institutions huge amounts of money for the privilege.</p><p>Because I was an avid blogger at that time and knew that people were learning from each other on the web all the time, I built a prototype social network for learning and tried to give it to them. They told me they didn’t want it (in a way that was much ruder than that). So I quit my job and ended up releasing it under an open source license so it wouldn’t be centralized and hold institutions hostage. That act of hubris set up the entirety of the rest of my career.</p><p>Which brings me to this article:</p><blockquote>“Thursday afternoon, millions of students at thousands of universities and K-12 schools were locked out of Canvas, a piece of catch-all education technology software that has become the de facto core of many classes. ShinyHunters, a ransomware group, hacked Canvas’s parent company and apparently stole “billions” of messages and accessed more than 275 million individuals’ data, <a href="https://www.wcnc.com/article/news/nation-world/canvas-hack-shinyhunters-schools-students-teachers-data-exposed/507-0f3f5973-3d68-45af-b309-666561b2bd87?ref=werd.io">according to the hacking group</a>. The group also locked students out of Canvas.”</blockquote><p><a href="https://linkletter.org/?ref=werd.io">Ian Linkletter</a> — a librarian who has been an active, and in my opinion, unceasingly correct edtech critic — is quoted as calling this “the biggest student data privacy disaster in history”. It need not have been the case; Canvas is theoretically <a href="https://github.com/instructure/canvas-lms?ref=werd.io">open source</a>. But <a href="https://werd.io/open-source-maintainers-need-to-go-in-with-open-eyes/">you can’t make money with open source alone</a>, and self-hosting is not something most institutions want to undertake. Canvas is a huge codebase with real quirks that is non-trivial to self-host, and the maintenance and infrastructure costs are real.</p><p>It’s also not clear that self-hosted infrastructure would be more resilient: a university could be subject to a ransomware attack with very little recourse. At the same time, the centralized nature of Canvas’s core offering means <em>every</em> institution that uses it, <a href="https://www.npr.org/2026/05/08/nx-s1-5815956/canvas-data-breach-school-finals?ref=werd.io">including over half of all US higher education institutions</a>, were in a hard place right in the middle of final exam season. Access is coming back, but at the time of writing, it hasn’t been fully restored. It’s a hard lesson about the dangers of putting everything in the hands of a single cloud provider.</p><hr><h3 id="you-couldnt-create-a-more-anti-news-internet-if-you-tried"><a href="https://mattdpearce.substack.com/p/you-couldnt-create-a-more-anti-news?ref=werd.io" rel="noreferrer">You couldn't create a more anti-news internet if you tried</a></h3><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 “nudges” as being a pro-information feature that search engines, LLM interfaces, and social media platforms could introduce:</p><blockquote>“Social media, too, could choose to feature quality news outlets as “defaults” or provide subtle “nudges” on content that prompt users to donate or subscribe to the news outlets providing high quality news videos on platforms like Instagram, which don’t pay for themselves.”</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’s true that nudges across all these platforms would have the effect he’s hoping for. But I think the tragedy is that there’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’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’re seeing increased regulations with respect to things like age verification, so introducing regulation is possible — 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’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’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’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’s more promising, particularly in a world where incumbent platforms are losing goodwill with the public. The kind of thinking that Matt’s done here is very useful in helping to design what those new platforms might look like.</p><p>We’re not in a great place and there’s a hard road ahead. I’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>Replacing my ISP router with a UniFi Cloud Gateway Max - Kev Quirkhttps://kevquirk.com/replacing-my-isp-router-with-a-unifi-cloud-gateway-max2026-05-15T18:37:00.000Z<p>So I recently <a href="https://kevquirk.com/upgrading-my-home-internet-to-full-fibre">upgraded my home internet</a> to full fibre, after which I also decided to upgrade my router as there were some things I wanted to do with my network that my ISP-provided router wasn't capable of.</p>
<p><a href="https://kevquirk.com/wifi-old-houses-painful">I replaced my mesh</a> system with a UniFi one a couple years ago, so it made sense to stick with the UniFi brand and go with one of their routers, so £250 later, I had a <em>Cloud Gateway Max</em> on its way to me.</p>
<p>I figured this would be a straightforward process, but my god was I wrong!</p>
<h2>First attempt</h2>
<p>So I took a backup of my Cloud Key<sup id="fnref1:1"><a href="https://kevquirk.com/replacing-my-isp-router-with-a-unifi-cloud-gateway-max#fn:1" class="footnote-ref">1</a></sup> config and figured I could unplug that, plug in the Cloud Gateway, restore the config and be done. I assumed there would be a couple things I needed to tweak, but for the most part, it would be a simple 10 minute job.</p>
<p>Fuck. No.</p>
<p>You see, dear reader, in order to configure the Cloud Gateway you need an internet connection. No internet connection, no configuration. So by unplugging my ISP router -thus killing the internet to my entire house - I couldn't even get to the point where I could enter my ISP credentials, let alone configure the bloody thing.</p>
<p>Without the internet connection all I could configure was the IP and MAC of the router. Absolutely pointless!</p>
<p class="notice">There may be a way of doing this without an internet connection, but I couldn't find it and it certainly wasn't obvious.</p>
<h2>Attempt #2</h2>
<p>So I had to reconnect my old rig - the ISP router, the Cloud Key, and access points. Then I hung the Cloud Gateway off the ISP router so it could get an internet connection.</p>
<p>Luckily this worked and I was finally able to configure the thing. After which I disconnected the Cloud Key, assuming the access points would all fail over to the Cloud Gateway when I restored the config backup from the Cloud Key.</p>
<p>Nope!</p>
<p>You see, the config back from the Cloud Key is a completely different file format (<code>*.unifi</code>) to what the Cloud Gateway was expecting (<code>*.unf</code>).</p>
<p>What the actual fuck!</p>
<h2>Attempt #3</h2>
<p>Soooooo back online went the Cloud Key, and I had to remove all 4 access points from there, just so I could <em>"adopt"</em> them with the Cloud Gateway. Then I had to manually setup my SSIDs and DHCP so it all matched the old rig.</p>
<p>But finally, after 3 hours of fucking around, a job that I thought would take 10 minutes was done.</p>
<h2>Final thoughts</h2>
<p>UniFi is really good kit and has lots of features, but I don't understand why it has to be so difficult to set up.</p>
<p>It feels like UniFi is the Apple of the networking world - they do everything they can to keep you in their ecosystem and up sell.</p>
<blockquote>
<p>Want our wifi? You're gonna need one of our routers, or this arbitrary piece of hardware for that.</p>
</blockquote>
<blockquote>
<p>Oh you want to move an AP to a new management device? Yeah, you can't just <em>move</em> it - you need to do these 5 steps instead.</p>
</blockquote>
<p>Had I not already spent over a thousand pound on this UniFi kit, I would have chucked it all on eBay and gone with something else, but alas <em>WiFi Apple</em> has me in their walled garden!</p>
<p>Anyway, it was a painful process, but it's working. And to be fair to UniFi, once it is all setup, it's rock solid and feature rich. I won't be upgrading again any time soon though, that's for sure!</p>
<p>Now I just need to familiarise myself with all the nifty features the Cloud Gateway offers, so I can improve my network. Fun times!</p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1">
<p>A Cloud Key is a stupid piece of hardware that is needed in lieu of a UniFi router. It controls the wireless access points. <a href="https://kevquirk.com/replacing-my-isp-router-with-a-unifi-cloud-gateway-max#fnref1:1" rev="footnote" class="footnote-backref">↩</a></p>
</li>
</ol>
</div> <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=Replacing%20my%20ISP%20router%20with%20a%20UniFi%20Cloud%20Gateway%20Max">reply to this post by email</a>, or <a href="https://kevquirk.com/replacing-my-isp-router-with-a-unifi-cloud-gateway-max#comments">leave a comment</a>.</p>
</div>UK Government Kicks Out Palantir - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=711692026-05-15T05:34:03.000Z<p>The UK Government, for all its faults, is pretty good at publishing contracts it has awarded. That's why I get depressed when I see rage-bait nonsense about how companies have been award "Top Secret" deals.</p>
<p>Right now you can go to <a href="https://www.contractsfinder.service.gov.uk">https://www.contractsfinder.service.gov.uk</a> and search for whichever <i lang="fr">bête noire</i> has you riled up. You might want to argue that the company is corrupt, incompetent, or overpriced - but you can't argue that its contract is secret. There's no conspiracy. There's no secrecy. There's not even "beware of the leopard" shenanigans. It's all out in the open<sup id="fnref:except"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:except" class="footnote-ref" title="Yes, there occasionally delays and some things are redacted either for privacy, security, or confidentiality. But, in the main, if the Government has spent money on it, it'll be published somewhere." role="doc-noteref">0</a></sup>.</p>
<p>The Government says who it paying money to.</p>
<p>But, of course, there are some things the Government <em>can't</em> say. It's rare for them to publicly disagree with a supplier, or call out how crappy they were. They need to maintain cordial relations with people<sup id="fnref:cathartic"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:cathartic" class="footnote-ref" title="Yes, I know it would cathartic to have a YouTube Shocked Face "Government SLAMS woeful supplier!!" but the long-term consequences make it unlikely." role="doc-noteref">1</a></sup>. They don't want to scare off new suppliers who can't risk being publicly humiliated. When contracts are cancelled or ended, it is usually done quietly.</p>
<p>So you need to learn to read between the lines.</p>
<p>Let's take this excellent blog post from the Ministry of Housing Communities and Local Government<sup id="fnref:mchlgchm"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:mchlgchm" class="footnote-ref" title="MHCLG is literally the worst acronym in a sea of unpronounceable alphabetti spaghetti. At least MOJ can be pronounced "Modge"!" role="doc-noteref">2</a></sup></p>
<p>"<a href="https://mhclgdigital.blog.gov.uk/2026/04/09/from-emergency-to-sustainability-creating-share-homes-for-ukraine-data/">From emergency to sustainability: creating Share Homes for Ukraine data</a>".</p>
<p>It's exactly the sort of blog post that some Civil Servants excel at writing. It clearly sets out how an ambitious and technically challenging project was delivered, why it is important, and who it benefits.</p>
<p>The blog post describes how the team…</p>
<blockquote><p>exited our contract with our supplier.</p></blockquote>
<p>And that:</p>
<blockquote><p>Moving to this in-house model is already saving MHCLG millions of pounds a year in running costs.</p></blockquote>
<p>They show user feedback for their new system saying:</p>
<blockquote><p>It’s easier to navigate than the previous system</p></blockquote>
<p>Of course, what they don't say is <em>who</em> supplied the previous system which was so costly and hard to use.</p>
<p>It was, of course, Palantir.</p>
<p>The <a href="https://www.contractsfinder.service.gov.uk/notice/b89e126f-8666-43d6-99b0-4e6a83a0c0a5">original contract (CPD4124104)</a> wasn't secret - although it was mired in <a href="https://www.ft.com/content/49de4d4d-5ac7-4f86-ac9e-17785be0aad9?syn-25a6b1a6=1">some controversy</a> as an urgent exemption to normal procurement rules<sup id="fnref:boring"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:boring" class="footnote-ref" title="My boring centrist dad position is that sometimes it makes sense to buy off-the-shelf in an emergency. If you find yourself abandoned after a night out, you order a taxi - you don't take up driving…" role="doc-noteref">3</a></sup>.</p>
<p>In 2023, the <a href="https://www.nao.org.uk/press-releases/investigation-into-homes-for-ukraine/">National Audit Office reported on the scheme</a> - including Palanitr's software. They said:</p>
<blockquote><p>The initial arrangement was put in place to help get the scheme up and running quickly. Consequently, the system did not undergo the usual research and testing that would be involved for the roll-out of a new digital system. There were initial issues such as the way it presented duplicated application data received from Home Office systems, and confusion from local authorities as to how to engage with the main data system.</p></blockquote>
<p>How bad was Palantir's software? I've sent in a <a href="https://www.whatdotheyknow.com/request/usability_and_other_feedback_fro">Freedom of Information request to find out</a>. But we can tell that it was bad enough to convince MHCLG to rewrite it themselves.</p>
<p>A lean Civil Service may not have the in-house capability to rapidly create a new service. But, as their blog post shows, when given suitable resources Civil Servants can often <em>outperform</em> the private sector. More importantly, the new software is under the Ministry's direct control. This <a href="https://github.com/communitiesuk/ukraine-sponsor-resettlement">open source</a> code is a triumph for sovereign technology.</p>
<p>MHCLG have shown the door to Palantir. They've built something better, easier to use, and cheaper.</p>
<p>I don't want to oversell this as the first victory in the war against this <a href="https://www.bbc.co.uk/news/articles/c4gjkj7975po">abominable company</a> - but I hope where MHCLG leads, others will follow.</p>
<hr>
<p>You can <a href="https://www.bbc.co.uk/news/articles/c2l2j1lxdk5o">read more about this story on BBC News</a>.</p>
<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">
<li id="fn:except">
<p>Yes, there occasionally delays and some things are redacted either for privacy, security, or confidentiality. But, in the main, if the Government has spent money on it, it'll be published somewhere. <a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:except" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:cathartic">
<p>Yes, I know it would cathartic to have a <a href="https://www.ign.com/articles/youtubes-infamous-shocked-face-thumbnails-could-be-on-the-way-out">YouTube Shocked Face</a> "Government SLAMS woeful supplier!!" but the long-term consequences make it unlikely. <a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:cathartic" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:mchlgchm">
<p>MHCLG is literally the worst acronym in a sea of unpronounceable alphabetti spaghetti. At least MOJ can be pronounced "Modge"! <a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:mchlgchm" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:boring">
<p>My boring <a href="https://inews.co.uk/news/politics/centrist-dads-introducing-new-bugbear-online-corbynites-92779">centrist dad</a> position is that sometimes it makes sense to buy off-the-shelf in an emergency. If you find yourself abandoned after a night out, you order a taxi - you don't take up driving lessons. <a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:boring" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=71169&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager">Read "Genre glitches and unexpected promotional phrases as a sign of AI writing" - Molly White's activity feed6a0616f591f30f1ebed42b262026-05-14T18:39:49.000Z<article class="entry h-entry hentry"><header><div class="description">Read: </div></header><div class="content e-content"><div class="article h-cite hcite"><div class="title"><a class="u-url u-repost-of" href="https://jilltxt.net/genre-glitches-and-unexpected-promotional-phrases-as-a-sign-of-ai-writing/" rel="bookmark">“<span class="p-name">Genre glitches and unexpected promotional phrases as a sign of AI writing</span>”</a>. </div><div class="byline"><span class="p-author h-card">Jill Walker Rettberg</span> in <span class="p-publication">her blog</span>. <span class="read-date"> Published <time class="dt-published published" datetime="2026-05-13">May 13, 2026</time>.</span></div><blockquote class="summary p-summary entry-summary">A genre glitch is a characteristic of LLM-assisted writing where the text suddenly switches genre, typically inserting a short promotional phrase full of sensory details into an informational text.</blockquote><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <time class="dt-published" datetime="2026-05-14T18:39:49+00:00" title="May 14, 2026 at 6:39 PM UTC">May 14, 2026 at 6:39 PM UTC</time>. </div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/feed/tag/artificial_intelligence" title="See all feed posts tagged "artificial intelligence"" rel="category tag">artificial intelligence</a>. </div></div></footer></article>52 actionable posts about building a culture of innovation - Werd I/O6a05bf302bc38300013f3a5e2026-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’s posts in my <a href="https://werd.io/tag/links">link roundups</a> every single week. Each one is genuinely gold — and I’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’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’ve been blogging since 1998 and I’m not convinced I’ve <em>ever</em> been that consistent. As he says, consistency compounds:</p><blockquote>“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'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.”</blockquote><p>I’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’ve been in board meetings at other orgs where his work has come up organically and I’ve been able to enthusiastically +1. If you’re not following him, there’s still time to correct that. He’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> — run at it.</p>A nice surprise in Things - Johnny.Decimalhttps://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've been diligent about pushing less-important category reviews out to a longer repeat interval. They must have 'shaken out' to the right cadence now. I didn't want to get review fatigue – I'd rather see them less, but spend quality time when we're together.</p>
<p>And I'm getting better at not dumping tasks in Today and letting them pile up because everything is urgent (it's not) and I'll do it all today (I won't). I'm careful with Today now and try to schedule achievable to-dos so it (me) doesn't get sad.</p>
<p>It's weird that I don't have <em>any</em> to-dos in there though. But we just finished a big project so I'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'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't let me in until I'd done a large software update that took ages. And made me late and feel unprofessional. Now I'm the annoying person on Zoom who isn'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'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'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 Feedhttps://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 "All Colours" 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 "Copy of Discover Mildliners". The <a href="https://www.zebrapen.com/pages/discover-mildliner">old page</a> still exists <a href="#fnref1" class="footnote-backref">⤾</a></p>
</li>
</ol>
</section>AI may be the new gatekeepers, but human connection is more needed than ever - Werd I/O6a046b54ef485b0001c83fdd2026-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 — AI adoption curves, data about social media use, qualitative evidence about how people are using AI to gather information today — point to the fact that it will.</p><p>This is the crux:</p><blockquote>“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 — 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.”</blockquote><p>For me, the framing of AI’s effects on existing information ecosystems while it establishes a new one was helpful. It’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 “<em>new</em> new gatekeepers”. 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’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’m biased towards New_ Public’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’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’m grateful for this encapsulated research, which I think will help to guide us all.</p>Stupidly Simple SVG Sparklines - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=633592026-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"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 124">
<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"></polyline>
</svg>
</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=>$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 <<< SVG
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 $svg_width $svg_height" class="chart">
<polyline
fill="none"
stroke="#F00"
stroke-width="3"
points="{$polyline_points}"/>
</svg>
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"><circle cx="12" cy="48" r="5" fill="#0074D955"><title>4,707 Views</title></circle>
</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 Fileshttps://joelchrono.xyz/blog/2026-w192026-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.Decimalhttps://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's how I feel about AI-generated apps. If I've sent you this link, it isn't personal. Please don't take it as such (even though I'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'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'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'm probably not going to look at it, and you shouldn'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't scale.</p>
<h2 id="enjoy-your-own-app">Enjoy your own app</h2>
<p>I'm not criticising AI-generated apps. It's amazing that you can make an app. What a time we live in.</p>
<p>But don't expect anyone else to care. They're busy. Making apps.</p>Spend time with your own words - Johnny.Decimalhttps://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're where the bulk of our stuff is, and they'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'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'm glad we did it. Because that's my business in there. Ideas that I've had, patterns, thoughts, notes-for-future-me. Yesterday morning I didn't really know what was in there. Now I do.</p>
<p>I don't think there'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't think you would be.</p>
<p>They're your words. They're thoughts that came out of your brain. If they're worth anything at all, spend some time with them.</p>Growing with my website - James' Coffee Bloghttps://jamesg.blog/2026/05/13/growing-with-my-website2026-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&&(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>
Note published on May 12, 2026 at 6:22 PM UTC - Molly White's activity feed6a036ff3b8f2d866aa0c97782026-05-12T18:22:43.000Z<article><div class="entry h-entry hentry"><header></header><div class="content e-content"><div class="media-wrapper"><a href="https://storage.mollywhite.net/micro/5c481aa6cb346f2eda7e_atlas-dandelions.jpg" data-fslightbox=c45d95486dc31360b307><img src="https://storage.mollywhite.net/micro/5c481aa6cb346f2eda7e_atlas-dandelions.jpg" alt="Atlas, a mostly black pit bull/husky/german shepherd mix, lies on his back in some green grass with dandelions on a sunny day. His front paws are bent up against his chest and his mouth is open." /></a></div></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp-block"><div class="timestamp">Posted: <a class="u-url" href="https://www.mollywhite.net/micro/entry/202605121421"><time class="dt-published" datetime="2026-05-12T18:22:43+00:00" title="May 12, 2026 at 6:22 PM UTC">May 12, 2026 at 6:22 PM UTC</time>. </a></div></div><div class="social-links"> <span> Also posted to: </span><a class="social-link u-syndication mastodon" href="https://hachyderm.io/@molly0xfff/116562996045777084" title="Mastodon" rel="syndication">Mastodon, </a><a class="social-link u-syndication bluesky" href="https://bsky.app/profile/molly.wiki/post/3mloftlk5xu2s" title="Bluesky" rel="syndication">Bluesky</a></div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/atlas" title="See all micro posts tagged "Atlas"" rel="category tag">Atlas</a>. </div></div></footer></div></article>Upgrading My Home Internet to Full Fibre - Kev Quirkhttps://kevquirk.com/upgrading-my-home-internet-to-full-fibre2026-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 Bloghttps://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<p>Go&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 <a href="https://github.com/trailofbits/gosentry">gosentry</a>, a fuzzing-oriented fork of the Go toolchain that keeps the standard <code>testing.F</code> workflow while using a stronger fuzzing stack underneath to tackle those issues.</p>
<p>With gosentry, <code>go test -fuzz</code> 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.</p>
<p>If you already have Go fuzz harnesses, you don&rsquo;t need to rewrite them. Point them at gosentry&rsquo;s binary and you get all of the above through the same <code>go test -fuzz</code> interface, with a few new flags:</p>
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">./bin/go <span class="nb">test</span> -fuzz<span class="o">=</span>FuzzHarness --focus-on-new-code<span class="o">=</span><span class="nb">false</span> --catch-races<span class="o">=</span><span class="nb">true</span> --catch-leaks<span class="o">=</span>true</span></span></code></pre>
<figcaption><span>Figure 1: Basic gosentry usage</span></figcaption>
</figure>
<p>gosentry keeps the harness API and changes the engine and the surrounding tooling — you just tweak the CLI.</p>
<p>You can also generate coverage reports from an existing campaign with <code>--generate-coverage</code>. Run it from the same package with the same <code>-fuzz</code> 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.</p>
<h2 id="why-we-built-gosentry">Why we built gosentry</h2>
<p>We started this project after we released <a href="https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/">go-panikint</a> to improve Go fuzzing’s integer overflow detection. We realized that integer overflow detection wasn’t enough. Go&rsquo;s fuzzing ecosystem was still missing techniques that Rust, C, and C++ researchers already use every day.</p>
<p>We often faced these gaps in our own security work using Go’s vanilla fuzzer:</p>
<ul>
<li>Program comparisons (path constraints) were impossible to solve: one complex <code>if</code> branch, and the Go fuzzer could stay stuck forever.</li>
<li>Grammar-based fuzzing was never an option.</li>
<li>Structure-aware fuzzing required additional manual work.</li>
<li>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.</li>
<li>Generating coverage reports from a fuzzing campaign was cumbersome.</li>
<li>Making the fuzzer crash on critical error logs required manual code changes.</li>
</ul>
<h2 id="same-harness-stronger-engine">Same harness, stronger engine</h2>
<p>Gosentry keeps the parts Go developers already know:</p>
<ul>
<li>Write a fuzz target with <code>testing.F</code>, as usual.</li>
<li>Create your initial corpus with <code>f.Add</code>.</li>
<li>Pass the input into <code>f.Fuzz</code>.</li>
</ul>
<p>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.</p>
<p>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.</p>
<h2 id="more-bugs-become-visible">More bugs become visible</h2>
<p>Another added value of gosentry is its capacity to turn more bad behaviors into failures that the vanilla Go fuzzer wouldn’t report.</p>
<p>It includes compiler-inserted integer overflow checks by default and optional truncation checks through the <a href="https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/">go-panikint</a> integration. It also lets you choose function calls that should stop the fuzzer. For example, you can use the <code>--panic-on</code> flag to stop fuzzing when <code>log.Fatal</code> 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.</p>
<p>It can also catch data race issues using the native Go race detector (<code>--catch-races</code>), and goroutine leaks through its <a href="https://github.com/uber-go/goleak">goleak</a> integration (<code>--catch-leaks</code>). Finally, timeouts can be caught at fuzz-time to help detect issues like infinite loops.</p>
<h2 id="better-inputs">Better inputs</h2>
<p>Gosentry improves input quality in two different ways, which solve different problems.</p>
<h3 id="struct-aware-fuzzing">Struct-aware fuzzing</h3>
<p>Go&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.</p>
<!-- markdownlint-disable MD010 -->
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">Input</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Data</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">S</span><span class="w"> </span><span class="kt">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">N</span><span class="w"> </span><span class="kt">int</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">func</span><span class="w"> </span><span class="nf">FuzzStructInput</span><span class="p">(</span><span class="nx">f</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">F</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">f</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">Input</span><span class="p">{</span><span class="nx">Data</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">),</span><span class="w"> </span><span class="nx">S</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;world&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">N</span><span class="p">:</span><span class="w"> </span><span class="mi">42</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">f</span><span class="p">.</span><span class="nf">Fuzz</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">,</span><span class="w"> </span><span class="nx">in</span><span class="w"> </span><span class="nx">Input</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nf">Process</span><span class="p">(</span><span class="nx">in</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre>
<figcaption><span>Figure 2: Supported gosentry harness with structured input</span></figcaption>
</figure>
<!-- markdownlint-enable MD010 -->
<p>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.</p>
<h3 id="grammar-based-fuzzing">Grammar-based fuzzing</h3>
<p>In this mode, gosentry uses <a href="https://github.com/nautilus-fuzz/nautilus">Nautilus</a> to generate and mutate grammar-valid inputs while LibAFL still drives the coverage-guided loop.</p>
<p>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 <code>{&quot;postOfficeBox&quot;: 123}</code> to <code>{postOfficeBox&quot;&quot;: &quot;&quot;&quot;&quot;&amp;%}</code>, while a more interesting generated input of <code>postOfficeBox</code> would be a much larger number like <code>u64.MAX</code>, giving <code>{&quot;postOfficeBox&quot;: 18446744073709551615}</code>. 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:</p>
<!-- markdownlint-disable MD010 -->
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">FuzzGrammarJSON</span><span class="p">(</span><span class="nx">f</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">F</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">f</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">`{&#34;postOfficeBox&#34;:123}`</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">f</span><span class="p">.</span><span class="nf">Fuzz</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">,</span><span class="w"> </span><span class="nx">jsonInput</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nf">ParseJSONFromString</span><span class="p">(</span><span class="nx">jsonInput</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre>
<figcaption><span>Figure 3: Grammar-based harness for our JSON parser</span></figcaption>
</figure>
<!-- markdownlint-enable MD010 -->
<p>The grammar format is a JSON array of rules:</p>
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Json&#34;</span><span class="p">,</span> <span class="s2">&#34;\\{\&#34;postOfficeBox\&#34;:{Number}\\}&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Number&#34;</span><span class="p">,</span> <span class="s2">&#34;{Digit}&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Number&#34;</span><span class="p">,</span> <span class="s2">&#34;{Digit}{Number}&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;0&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;1&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;2&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;4&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;5&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;6&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;7&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;8&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s2">&#34;Digit&#34;</span><span class="p">,</span> <span class="s2">&#34;9&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span></span></span></code></pre>
<figcaption><span>Figure 4: Definition of our postOfficeBox JSON grammar</span></figcaption>
</figure>
<p>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.</p>
<h2 id="what-it-has-found-already">What it has found already</h2>
<p>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:</p>
<ul>
<li><a href="https://github.com/ethereum-optimism/optimism/issues/19334">Unknown batch type panics and causes denial of service in kona-protocol</a></li>
<li><a href="https://github.com/ethereum-optimism/optimism/issues/19333">Kona and op-node can disagree on brotli channels</a></li>
<li><a href="https://github.com/ethereum-optimism/optimism/issues/19335">Kona frame parsing mismatch against op-node and OP Stack Specs</a></li>
<li><a href="https://github.com/bluealloy/revm/issues/3458">Failed deposit in op-revm stopping with <code>OutOfFunds</code> does not bump nonce, leading to a state root mismatch against other clients</a></li>
</ul>
<p>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.</p>
<p>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.</p>
<p>The project is available on <a href="https://github.com/trailofbits/gosentry">GitHub</a> and includes documentation for each feature described above.</p>
<p>If you’d like to read more about fuzzing, check out the following resources:</p>
<ul>
<li>Our <a href="https://appsec.guide/docs/fuzzing/"><strong>fuzzing chapter</strong></a> in the Testing Handbook</li>
<li><a href="https://blog.trailofbits.com/2024/02/23/continuously-fuzzing-python-c-extensions/"><strong>Continuously fuzzing Python C extensions</strong></a></li>
<li><a href="https://blog.trailofbits.com/2020/06/05/breaking-the-solidity-compiler-with-a-fuzzer/"><strong>Breaking the Solidity Compiler with a Fuzzer</strong></a></li>
</ul>
<p>As always, <a href="https://trailofbits.com/contact/"><strong>contact us</strong></a> if you need help with your next Go project or fuzzing campaign.</p>Position or Perish: The Narrative Blueprint - Westenberg6a02795c65b5c3000191635d2026-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'd been unprofitable for thirteen straight. </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: </p><p><em>"Avis is only No. 2 in rent a cars. So we try harder."</em></p><p>Within a year, Avis had moved from $3.2 million in losses to $1.2 million in profit. The cars hadn't changed. The locations hadn't changed. The pricing hadn'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: "What is this, and why should it matter to me right now?"</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'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'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's head, where there'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're ready to launch.</p><p>This is both wrong - and expensive.</p><p>Positioning is upstream of marketing. It'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't agree on what the company does.</p><p>I've worked with companies that had product-market fit and were still failing because no two people inside the building could finish the sentence: "We are the _____ for _____." When the founders can't agree, the sales team improvises, and the marketing team writes copy that doesn'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'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? "Businesses," "developers," and "creators" are broad nouns that fall apart under any pressure. A real audience description names a role and a moment. "Heads of compliance at mid-market fintechs trying to pass their first SOC 2" is an audience. "Modern professionals" 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's the one that matters most. Customers don't compare you to nothing. They compare you to the spreadsheet they'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't claim the wedge.</li><li>The fourth is the wedge. What'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'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'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'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 “software” itself. "No software." 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'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're claiming.</p><p>The wrong enemy is another startup nobody's heard of. The wrong enemy is the abstract status quo of "manual processes," 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 "create a new category and dominate it," and most who try this fail because they don'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'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're a seed-stage company with $2 million in the bank, you can'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'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'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'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'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'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'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's no such thing as neutral copy and there should be no such thing as filler. A hero headline that says "Empower your team" 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. "We process two billion dollars a year in same-day payouts for marketplaces" is a positioning sentence. "We make payments easy" 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's, and see if the sentences still make sense.</p><p>If they do, you'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'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'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'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'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'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's muddy, every hire becomes a war.</p><p>I'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'll tell their next employer about this job will sound impressive or embarrassing. We’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'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't cover, and customers are confused about what they'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'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'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: "We are the _____ for _____ who want to _____ instead of _____."</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'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't know what it is.</p><p>Run the exercise this week. Don'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't open a new marketing channel until they'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'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't change because the position doesn't change. The position doesn't change because Warren Buffett worked out what he believed early and refused to negotiate with the market about it.</p><p>You don’t have fifty years. At most, at the absolute stretch, you have 2-3 before the company either compounds into something or doesn'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>