Shellsharks Blogroll - BlogFlock2026-02-04T15:37:34.768ZBlogFlockEvan Boehs, Robb Knight, destructured, Aaron Parecki, Westenberg, Werd I/O, fLaMEd, James' Coffee Blog, gynvael.coldwind//vx.log (pl), Molly White, joelchrono, Trail of Bits Blog, Posts feed, Kev Quirk, cool-as-heck, Adepts of 0xCC, Sophie Koonin, cmdr-nova@internet:~$, <span>Songs</span> on the Security of Networks, Johnny.Decimal, Hey, it's Jason!, Terence Eden’s BlogForgejo Support for EchoFeed - Robb Knight • Posts • Atom Feedhttps://rknight.me/blog/forgejo-support-for-echofeed/2026-02-04T12:38:55.000Z<p>I've just merged in support for <a href="https://forgejo.org">Forgejo</a> to EchoFeed. Forgejo is a "<em>self-hosted lightweight software forge</em>" aka "We have GitHub at home"<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>. <a href="https://neatnik.net">Adam</a> is <a href="https://source.tube">running an instance</a> as part of <a href="https://omg.lol">omg.lol</a>.</p>
<p>It works the same at the GitHub integration with one exception: no OAuth. Forgejo can exist on any domain, like Mastodon, but it doesn't allow for creating applications (like EchoFeed) on-the-fly. Instead, it uses access tokens which isn't as convenient but I didn't want to create applications on every instance someone might want to use. Here's a screenshot of the required permissions but <a href="https://help.echofeed.app/services/#foregjo">check the docs</a> for the details on setting the right permissions.</p>
<figure><img src="https://cdn.rknight.me/echofeed/forgejo-access-token-settings.jpg" alt="Forgejo settings required for EchoFeed" /></figure>
<p>Forgejo support is available to everyone right now.</p>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>I don't intend this to be mean but the uncanny valley of how close the UI is to GitHub is hard to miss <a href="#fnref1" class="footnote-backref">⤾</a></p>
</li>
</ol>
</section>Book Review: The Examiner - Janice Hallett ★★★★⯪ - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=666252026-02-04T12:34:22.000Z<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/examiner.webp" alt="Book cover featuring a scorpion." width="200" class="alignleft size-full wp-image-66629"/>
<p>I've thoroughly enjoyed all of <a href="https://shkspr.mobi/blog/tag/janice-hallett/">Janice Hallett's previous crime books</a>. The Examiner is, frankly, more of the same - and I'm happy with that!</p>
<p>You, the reader, are given a series of transcripts and have to work out what crime (if any) has been committed. You don't find out who the victim(s) is/are until reasonably far through the story. The characters are well realised (although a little similar to some of her others). The twists are shockingly good and will make you flick back to see if you could have spotted them.</p>
<p>Hallett is <em>exquisite</em> at building tension through the slow drip-drip-drip of reveals. OK, so the transcripts are a bit unrealistic but they make a good scaffold. While it might be nice to include user avatars on the WhatsApp messages, the characters' voices are unique enough to distinguish them easily.</p>
<p>Much like <a href="https://shkspr.mobi/blog/2025/07/book-review-the-mysterious-case-of-the-alperton-angels-by-janice-hallett/">The Mysterious Case of the Alperton Angels</a>, the book plays around with symbolism and the nature of faith. You may find yourself sympathising with the characters and then quickly recanting!</p>
<h2 id="technical-issues"><a href="https://shkspr.mobi/blog/2026/02/book-review-the-examiner-janice-hallett/#technical-issues">Technical Issues</a></h2>
<p>Viper, the publisher, seem to have messed up the structure of this eBook. Despite being published in 2024, they're using an <em>ancient</em> and obsolete version of the <a href="https://github.com/FriendsOfEpub/Blitz/">Blitz ePub CSS</a> which itself was archived back in 2020. As well as strange indents, there's a hard-coded 2em margin only on the right.</p>
<p>Accessibility is poor. All the abbreviations use the <code><abbr></code> element. But some kind of automated find-and-replace has mangled most of them. For example, the "Masters degree in Multimedia Art (Full-Time Programme)" is shortened to "MMAM(FTP)" and then given the nonsensical abbreviation of "Molecular Area Per Molecule (File Transfer Protocol)"!</p>
<p><a href="https://shkspr.mobi/blog/2025/08/how-long-does-it-take-to-upgrade-an-ebook/">Much like before</a> I've written to them asking them to correct it.</p>
Boob Tube Activity - Cool As Heckhttps://cool-as-heck.blog/boob-tube-activity2026-02-03T19:17:29.000Z<div>My wife and I are still watching a lot of the Taskmaster back episodes. We've slowed down a bit so we don't go through them so fast. We are watching the seasons in ordered chunks, but the chunks are out of order. We started with series 19 because of Jason Mantzoukas, then we watched series 20. Then we went back and watched 17, 18, and 19, but then skipped further back to series 4 and have been watching in order from there. I think now we're about to finish series 12 now. At some point we'll watch 1-3. We were so bummed we couldn't get tickets to the US live show in DC.</div>
<div><br></div>
<div>This week we started watching Wonder Man, the new Marvel TV show. He's a bit more obscure Marvel comics character, but the show is high quality and reminds me a bit of Loki. I highly recommend it. </div>
<div><br></div>
<div>Another show we jumped into this week is A Knight Of The Seven Kingdoms. This is another show set within the Game of Thrones universe, but about 90 years before that show, I think. It's based on a series of novellas, one of which is The Hedge Knight. It has a much lighter and more comical tone than Game of Thrones or House of the Dragon. We're two episodes in and so far we are loving it.</div>
The cost of running OpenBenches.org - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=672792026-02-03T12:34:16.000Z<p>After my recent presentation at FOSDEM, someone asked a pretty reasonable question. What does it cost to run <a href="https://openbenches.org/">OpenBenches</a>?</p>
<p>It is, thankfully, surprisingly cheap! In part, that's because it is a relatively simple tech stack - PHP, MySQL, a couple of API calls to external services. It was designed to be as low cost while also being useful. Here's the breakdown:</p>
<h2 id="hosting-171-per-year"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#hosting-171-per-year">Hosting - £171 per year</a></h2>
<p>Our biggest expense but, I think, our most reasonable. <a href="https://krystal.io/hosting">Krystal</a> charges around £342 for a 2 year contract. That includes unlimited bandwidth and storage, as well as the domain name. We have nearly 400GB of photos and bot scraping means we can use over 900GB of bandwidth per month - so Krystal give us a rather good deal!</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/02/April-Bandwidth.webp" alt="Graph showing sudden spikes in data use as our bandwidth is consumed by bots." width="930" height="355" class="aligncenter size-full wp-image-67531"/>
<p>Use <a href="https://www.awin1.com/cread.php?s=3990878&v=117205&q=524267&r=1062999">this affiliate link and code <code>EDENT</code></a> to get a small discount.</p>
<h2 id="stadia-maps-us20-month"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#stadia-maps-us20-month">Stadia Maps - US$20 / month</a></h2>
<p>Geocoding is surprisingly hard to do locally. We need to transform latitude and longitude into addresses, and then back again. <a href="https://stadiamaps.com/">Stadia Maps</a> cost about the same as our hosting! What's rather annoying is that we only use about half the API calls in our plan. We need to find a cheaper solution.</p>
<h2 id="mapping-free"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#mapping-free">Mapping - Free!</a></h2>
<p>When we used Stadia for drawing maps, we regularly ran over our quota. So we switched to <a href="https://openfreemap.org/">OpenFreeMap</a> which produces gorgeous interactive maps.</p>
<p>The service has been rock solid and very responsive to bugs on GitHub.</p>
<h2 id="logo-us5"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#logo-us5">Logo - US$5</a></h2>
<p>I'm not a good designer, so we bought a <a href="https://thenounproject.com/icon/park-923893/">logo from The Noun Project</a> and then coloured it in. Bargain for a fiver!</p>
<h2 id="image-cdn-free"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#image-cdn-free">Image CDN - Free!</a></h2>
<p>Although we have unlimited bandwidth with Krystal, we're only located in one region - the UK. <a href="https://images.weserv.nl/">WeServ</a>. It's also pointless serving full resolution images to small screens.</p>
<p>So WeServ offers free image resizing and global CDNs. Personally, I'm not a fan of CloudFlare (their CDN partner) so I'm looking to change provider.</p>
<h2 id="ocr-free"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#ocr-free">OCR - Free!</a></h2>
<p>People don't want to type in the inscription of the photo, so we use <a href="https://cloud.google.com/vision/docs/ocr">Google Cloud Vision</a>.</p>
<p>We send less than 1,000 requests per month - <a href="https://cloud.google.com/vision/pricing">so we're inside their free tier</a>. If we get more popular, that'll get more expensive. But I don't know of a local-first OCR which is as good as Google's. Sadly, Tesseract is rubbish for extracting text from photos.</p>
<h2 id="authentication-free"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#authentication-free">Authentication - Free!</a></h2>
<p>We don't want to store anyone's passwords. The <a href="https://auth0.com/pricing">free tier of Auth0</a> allows us to do social login for up to 25,000 monthly users. Which is more than enough for us.</p>
<p>Sadly, Auth0 don't support the Fediverse, <a href="https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/">so I had to build my own "Log-in with Mastodon" service</a>.</p>
<p>As much as we'd like to run social login locally, we simply don't want to be responsible for securing users' details & API keys.</p>
<h2 id="software-free"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#software-free">Software - Free!</a></h2>
<p>As per <a href="https://www.openbenches.org/colophon">the OpenBenches colophon</a> we use a lot of cool FOSS. Small JS libraries, big PHP frameworks, and everything in between.</p>
<h2 id="income"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#income">Income</a></h2>
<p>Thanks to <a href="https://github.com/sponsors/openbenches/">GitHub Sponsors</a> we make a whopping US$3 per month!</p>
<p>Similarly, our <a href="https://opencollective.com/openbenches">OpenCollective Sponsors</a> brings in about £3 per month.</p>
<p>Merchandising! You can <a href="https://openbenches.myspreadshop.co.uk/all">buy OpenBenches branded t-shirts, mugs, and hats</a>. That nets us about £20 per year</p>
<p>Call it roughly £80 income. OK, it is better than nothing - but doesn't even cover a quarter of our costs. Sometimes people give us a higher donation privately, which is also very welcome. These people are <a href="https://github.com/openbenches/openbenches.org?tab=readme-ov-file#supporters">listed on our README</a>.</p>
<h2 id="total"><a href="https://shkspr.mobi/blog/2026/02/the-cost-of-running-openbenches-org/#total">Total</a></h2>
<p>On the assumption that our time is worthless (ha!) and that we only rarely go over our providers' API limits, and we get in <em>some</em> revenue, the cost of running OpenBenches is less than £300 per year.</p>
<p>That's not bad for a fun little hobby. People certainly spend more than that on Funkopops, vaping, and mechanical keyboards!</p>
<p>Nevertheless, I'm always slightly worried that we'll go viral and have an unexpectedly high bill from our API providers.</p>
<p>I would love to be able to hire a proper designer to make the site look a bit nicer. I also want to be able to buy a modern iPhone so that I can test it in the latest Safari.</p>
<p>If you have any suggestions for cutting costs, or non-scummy ways to help us raise funds, please drop a comment below.</p>
22.00.0182 JDex deep-dive: data and storage options - Johnny.Decimalhttps://johnnydecimal.com/22.00.0182/2026-02-03T10:59:56.000Z<h1 id="jdex-deep-dive-data-and-storage-options">JDex deep-dive: data and storage options</h1>
<p>This post is a deep-dive into two aspects of your JDex: whether or not you use it to store data, and the different ways you can store the JDex itself. This article is long, and isn't a tutorial; this is reference material that I can now link to when common questions arise.</p>
<h2 id="our-analogy-the-library">Our analogy: the library</h2>
<p>This analogy courtesy of <a href="https://discord.com/channels/822215537589354566/1267671288252600412/1464526017090556095">Moriarty on Discord</a>, who said:</p>
<blockquote>
<p>…the revelation was realising that my filesystem, (long-form) notes folder, physical filing cabinet etc were the bookshelves in a library, and my JDex was the index card drawer. One (the card index) describes the shelves and what's on them, the other (the shelves) have the content.</p>
</blockquote>
<p>That's brilliant. Let's make it really explicit. Put yourself in your local city library, some time in the 1960s. 🕺🏼</p>
<h3 id="index-cards">Index cards</h3>
<p>Before computers, libraries kept records of books on index cards.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="A photograph of a metal filing cabinet, one drawer open, full of cardboard index cards." class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182A-Filing_cabinet--0-cx-640x426.jpg" width="640" height="426"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182A. The good old days.</figcaption> </picture>
<p>Crucially, you can think of <strong>the index card</strong> as a representation of <strong>the book itself</strong>. If a card doesn't exist, the book might as well not exist. To find a book in a library you don't start <em>at a bookshelf</em>. You start <em>with the index of books</em>. Here's the process.</p>
<ol>
<li>Go to the index.</li>
<li>Using the structure of the index (Dewey, in the case of your library) find the book in question.</li>
<li>The index card will tell you where the book is physically located.</li>
<li>Assuming the book is in the building -- it might be out on loan -- walk to the location indicated on the card and get the book.<sup><a href="#user-content-fn-library" id="user-content-fnref-library" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup></li>
</ol>
<h3 id="your-jdex">Your JDex</h3>
<p>Your Johnny.Decimal index (JDex) was designed to work <em>exactly</em> the same way. Your Johnny.Decimal IDs are the index cards. Each ID belongs to a <strong>category</strong>, which is analogous to the drawer. And -- not shown here because the diagrams are busy enough already -- we understand that each <strong>category</strong> belongs to an <strong>area</strong> just like each drawer is housed in a cabinet.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="A line diagram. A purple box labelled 'Index card drawer = category e.g. 12' contains blue cards, one of which is labelled 'Index card = ID, e.g. 12.17'." class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182B-Category_ID_diagram--0-cx-540x468@2x.png" width="270" height="234"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182B. Categories hold IDs.</figcaption> </picture>
<p>This is why I say the JDex is the <em>most important thing</em> in your system. A library without a catalogue is no longer a library: it's just a room full of books. Your life without a JDex is no longer a Johnny.Decimal system: it's just a bunch of files (even if they are neatly organised).</p>
<h3 id="metadata">Metadata</h3>
<p>Metadata is 'data that defines and describes the characteristics of other data' (<a href="https://en.wikipedia.org/wiki/Metadata">Wikipedia</a>). So if data is a book's contents, metadata is its publication date, ISBN number, current location, and so on.</p>
<p>We use this all the time without being conscious of it: the last modified time of a file is metadata. The fact that some piece of knowledge is in your email is metadata. (The knowledge itself being data.)</p>
<p>The thing about metadata is that it's typically tiny in comparison to the thing that it represents. As a result, we don't have to find some new place to store it. We already have one: <strong>the index entry</strong>.</p>
<p>For the library, this means writing this stuff directly on the index card. For your JDex, it means that your IDs' metadata is <strong>always</strong> stored directly with the JDex entry. Metadata is a <em>fundamental component</em> of the entry: it's not some separate thing to manage.</p>
<p>Here's how that might look with a handful of entries from the Life Admin System. Remember: purple box = category. Blue note = ID.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="The previous diagram, but now we have 3x of them. Each purple box is labelled with the number of a Johnny.Decimal category, and each blue note that it contains is labelled with an ID from that category." class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182C-3x_categories_with_IDs--0-cx-684x1728@2x.png" width="342" height="864"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182C. IDs from the Life Admin System with metadata.</figcaption> </picture>
<h3 id="metadata-should-be-standardised">Metadata should be standardised</h3>
<p>You should decide on a common set of metadata 'keys' and use them consistently. This allows you to query it later: for example, finding all entries where <code>Last updated:</code> is after '2026-01-29', or all entries where <code>Location:</code> is 'fireproof lock box'.</p>
<p>This is only possible if you always call it <code>Location</code>. If you sometimes call it <code>Where is it?</code>, that's now a different thing.</p>
<blockquote>
<p>Nerd note: we call these key/value pairs. <strong>Keys</strong> are standard. Their <strong>values</strong> change. As keys are special, I'll show them <code>like this</code> in this post.</p>
</blockquote>
<p>This is an important distinction as we consider what's metadata vs. data, below.</p>
<p>In the near future, the Johnny.Decimal system will recommend a standard set of metadata keys. If I use it in this post, you may assume it will be in that standard.</p>
<h3 id="above-the-line">'Above the line'</h3>
<p>Note the horizontal line in these diagrams. That's deliberate: in my JDex, I use a line to separate <strong>metadata</strong> from <strong>data</strong>. Metadata is always 'above the line'. We'll see data 'below the line' shortly.</p>
<ul>
<li>Above the line: the book's metadata.</li>
<li>Below the line: the book's contents.</li>
</ul>
<h2 id="storing-data-in-your-jdex">Storing data in your JDex</h2>
<p>In contrast to metadata, your library's index cards weren't designed to store the data that they represent. They aren't the book's contents.</p>
<p>But nor are computers 5×7" pieces of cardboard stored in a little metal box. So in this new world, you might choose to extend the usefulness of your index entries by using them to <strong>store data</strong>.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="The blue ID card from our previous example now has a bunch of data in the form of notes. The ID is about your passport, and the data is about its renewal and cost." class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182D-ID_with_data--0-cx-684x828@2x.png" width="342" height="414"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182D. An ID entry with data 'below the line'.</figcaption> </picture>
<p>Here, we're still recording the location of your passport as metadata 'above the line'. But we're also storing a bunch of other data 'below the line'.</p>
<blockquote>
<p>Nerd note: we call this 'structured' vs. 'unstructured' data. Here <strong>metadata</strong> is structured, with standard <strong>keys</strong>. Our below-the-line <strong>data</strong> is unstructured: it's different for each entry.</p>
</blockquote>
<p>This is what I do and recommend. It's simple. Everything's in one place. It's very hard to lose information, and very quick to retrieve it.</p>
<p>To address the alternative scenario, we need to expand this model.</p>
<h2 id="storing-data-outside-your-jdex">Storing data outside your JDex</h2>
<p>Back to the physical library. There, index cards point at books, and books contain data.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="Our block diagram now shows the representation of a book in purple/blue on the left, pointing to the contents of the book (Dickens' _A Tale of Two Cities_) on the right. _It was the best of times, it was the worst of times…_" class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182E-Diagram_of_book--0-cx-1476x504@2x.png" style="background-color: #feede6;" width="738" height="252"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182E. A book's index card points to the book's contents.</figcaption> </picture>
<p>In exactly the same way, we can move the data out of our JDex note and into its own file.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="The same diagram now represents our JDex on the left in purple/blue, and where we previously had notes in the JDex entry, they've been moved out to .txt files on the right in orange. This mirrors the contents of the book from the previous diagram." class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182F-External_data--0-cx-1476x756@2x.png" style="background-color: #feede6;" width="738" height="378"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182F. A JDex entry points to its data.</figcaption> </picture>
<p>Here, <code>11.12 Passports, residency, &…</code> is an ID folder in our filesystem (orange). We've created 2 files there (yellow): one for our partner's passport, and one for our own. And we've moved the data out of the index entry into these text files.</p>
<p>To be sure we don't forget about this data, we've reminded ourselves about it using a <code>Data</code> property. (This is optional. But if in doubt, it's worth doing. It takes no time.)</p>
<h3 id="a-note-on-location">A note on <code>Location</code></h3>
<p>Remember that this metadata relates to <strong>our passports</strong>. As in, the little book you show at immigration: <em>not</em> the Johnny.Decimal ID that is the <em>concept</em> of your passport.</p>
<p>That's why <code>Data</code> is split from <code>Location</code>. We have <em>data about the passports</em>, which is in some place. And, separately, the <em>(physical) location of the passports</em>.</p>
<p>But let's not get distracted. I'll have more to say about <code>Location</code> in a future post.</p>
<h3 id="recap">Recap</h3>
<p>To recap, we've introduced two scenarios.</p>
<ol>
<li>You store data in your JDex entry, below-the-line.</li>
<li>You store data externally, and (optionally) reference it above-the-line.</li>
</ol>
<p>It might be interesting to note that here at JDHQ we use both of these methods. Johnny tends to prefer the first. Lucy, perhaps because of her career as a copywriter and editor, leans towards the second. They happily co-exist.</p>
<h3 id="quadrant-chart">Quadrant chart</h3>
<p>Let's introduce the beginnings of what will become a quadrant chart. This will help us to orient these concepts relative to each other.</p>
<p>The left/right split represents the scenarios just discussed.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="A square, split into two rectangles. On the left, with an axis label of 'Data in JDex', there's a data point labelled 'Data below-the-line'. On the right, axis labelled 'Data externally', a data point 'Data in filesystem'." class=" auto-dark astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182G-Quadrant_1--0-cx-930x930@2x.png" width="465" height="465"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182G. All quadrant charts are born as two rectangles. True fact.</figcaption> </picture>
<h3 id="this-is-a-continuum">This is a continuum</h3>
<p>There's a hard line down the middle of this diagram, but life isn't like that. The reality is that this is a continuum, with most cases somewhere in the middle.</p>
<p>To the far left of this diagram is the situation where you <em>exclusively</em> store data in your JDex. This is unrealistic: will you <em>never</em> save a file? Files are data. So when I say that you 'store data below-the-line', I mean <em>some</em> data: usually textual data, as it's natural to add that to the existing JDex entry. As soon as you also save a file, or keep <em>any</em> artefact related to this ID outside the JDex entry, you've moved away from that left edge.</p>
<p>The right edge of this diagram is somewhere you might actually exist. In this situation, you <em>never</em> store <em>any</em> data in your JDex. For example, your JDex might be an Excel spreadsheet, with one row for each ID.<sup><a href="#user-content-fn-excel" id="user-content-fnref-excel" data-footnote-ref="" aria-describedby="footnote-label">2</a></sup> Excel is a terrible place to try to write any sort of long-form text, so it would make sense for <em>no</em> data to be stored there.</p>
<p>This diagram is just useful for us to map out all the ways we can do it. But none of them is more correct than the others. It's all preference.</p>
<h2 id="where-is-your-jdex-stored">Where is your JDex stored?</h2>
<p>There's another fundamental question to be addressed, and it relates to the storage <strong>of your JDex</strong>. We've established that you <em>have</em> a JDex. Where is it?</p>
<p>This is another continuum, the opposing sides being:</p>
<ol>
<li>Store your JDex as individual files in your filesystem.</li>
<li>Store your JDex as some other artefact, not in your filesystem.</li>
</ol>
<p>Let's explore these options.</p>
<h3 id="jdex-as-individual-files-in-your-filesystem">JDex as individual files in your filesystem</h3>
<p>What we mean here is simply that each JDex entry is an individual file, usually a text file, often formatted with Markdown.</p>
<p>You <em>could</em> manage these manually, but it's far more common to use an application, and the most common of those is <a href="https://obsidian.md">Obsidian</a>. For those who don't know it, you point it at a folder and it'll show you the structure of that folder and all of the Markdown files in it. Select a file from the left, edit it on the right. JDHQ provides downloads for the Life Admin and Small Business Systems that are designed to work with Obsidian.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" srcset="/img/v6/22.00.0182H-Obsidian--0-light-cx-1426x990@2x.png" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" srcset="/img/v6/22.00.0182H-Obsidian--0-dark-cx-1426x990@2x.png" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" srcset="/img/v6/22.00.0182H-Obsidian--0-light-cx-1426x990@2x.png" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" srcset="/img/v6/22.00.0182H-Obsidian--0-dark-cx-1426x990@2x.png" class="astro-3zw7efbj"> <img alt="A screenshot of Obsidian. The left pane shows a folder structure which mirrors Johnny.Decimal. The right pane show the content of the entry." class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182H-Obsidian--0-light-cx-1426x990@2x.png" width="713" height="495"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182H. Obsidian.</figcaption> </picture>
<p>People enjoy Obsidian because it sits <em>over</em> your files: it's a convenient utility. But if you get sick of Obsidian, or if they decide to charge $500/year for a licence, or if you want to give some other app a try, you can just stop using it. All of your files are still Markdown files in a folder that you control.</p>
<p>The vertical axis of our chart now represents where your files are stored. Obsidian sits in the top half, where your JDex is 'files in your filesystem'. It spans both top-left and top-right quadrants as you still have the choice of where to store data: in your JDex, or externally.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="Our quadrant chart now has quadrants. The vertical axis has been labelled with 'JDex stored in filesystem' at the top, and 'JDex elsewhere' at the bottom." class=" auto-dark astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182J-Quadrant_2--0-cx-930x930@2x.png" width="465" height="465"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182J. Quadrant chart with Obsidian represented.</figcaption> </picture>
<h3 id="jdex-stored-elsewhere">JDex stored elsewhere</h3>
<p>There are a <em>lot</em> of options in this bottom half, so let's explore the simplest.</p>
<p>The other app that I love and support (with specifically-formatted downloads from JDHQ) is Bear. Superficially, Bear is identical to Obsidian: list on the left, editor on the right.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" srcset="/img/v6/22.00.0182K-Bear--0-cx-light-1426x1084@2x.png" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" srcset="/img/v6/22.00.0182K-Bear--0-cx-dark-1426x1084@2x.png" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" srcset="/img/v6/22.00.0182K-Bear--0-cx-light-1426x1084@2x.png" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" srcset="/img/v6/22.00.0182K-Bear--0-cx-dark-1426x1084@2x.png" class="astro-3zw7efbj"> <img alt="A screenshot of Bear. The left pane shows a list of JDex entries. The right pane shows the content of the entry." class=" astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182K-Bear--0-cx-light-1426x1084@2x.png" width="713" height="542"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182K. Bear.</figcaption> </picture>
<p>But there is a crucial difference: Bear manages these JDex entries entirely for you. There's no concept of 'text files on your disk' to manage. There's no option in Bear to change the location of these files. You can't, outside of Bear, go and look at them. Another app can't edit them. You can't put them in a shared folder and collaborate with your partner.</p>
<p>(Technically, in fact, they aren't even a collection of text files. Rather, Bear manages them <a href="https://bear.app/faq/where-are-bears-notes-located/">using a database</a> which they 'highly recommend' that you do not touch.)</p>
<p>This sounds limiting, and in many ways it is. Why would you want this? Well, it's a <em>lot</em> simpler. You load your JDex files into Bear once, and then never have to think about where they are. Want them on your iPhone? Just install Bear and they'll appear. They're harder to lose because Bear stores them in your iCloud Drive so if you drop your laptop in a lake, no worries.<sup><a href="#user-content-fn-not-a-backup" id="user-content-fnref-not-a-backup" data-footnote-ref="" aria-describedby="footnote-label">3</a></sup></p>
<p>Many apps work like this: Apple Notes, Craft, Evernote, Google Keep, Notion, and OneNote to name a few.<sup><a href="#user-content-fn-export" id="user-content-fnref-export" data-footnote-ref="" aria-describedby="footnote-label">4</a></sup></p>
<p>Let's keep it simple and add Bear to our quadrant chart.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="The previous quadrant chart with 'Bear' added in the lower half." class=" auto-dark astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182L-Quadrant_3--0-cx-930x930@2x.png" width="465" height="465"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182L. Quadrant chart with Bear represented.</figcaption> </picture>
<p>The point of this distinction is that when you're using a method in the bottom half of this chart -- more of which we'll see shortly -- the decision of <em>where to store your JDex</em> is made for you. This is one less thing for you to have to manage.</p>
<h2 id="where-are-your-jdex-files">Where are your JDex files?</h2>
<p>A question naturally arises: if we're talking about you storing your JDex as 'files in your filesystem', where are those files? As usual, there are a few options.</p>
<p>Ignoring your JDex for a moment, here's a simple representation of your filesystem. As in, the Johnny.Decimal structure, probably in your Documents folder or on a cloud drive, where you save all your stuff.</p>
<div class="JDBlock"> <pre>▓ 10-19 Life administration/</pre><pre>▓ └── 11 Me & other living things/</pre><pre>▓ ├── 11.11 Birth certificate & proof of name</pre><pre>▓ ├── 11.12 Passports, residency, & citizenship</pre><pre>▓ └── …and so on</pre><pre>__________________</pre><pre>Figure 22.00.0182M.</pre> </div>
<blockquote>
<p>The dark blocks on the left will make sense shortly. These tree diagrams don't work well on mobile, sorry. I've made sure that they are clear and flow properly at larger sizes.</p>
</blockquote>
<p>It's pretty obvious that if you had a PDF that you needed to save -- say your latest passport renewal -- you'd put it in 11.12. Because it's a file, that you're saving in your filesystem. No new concepts there.</p>
<p>So if we're storing our JDex as files in our filesystem, it must be <em>in here somewhere</em>. Where else would it be?</p>
<p>This is one of the IDs that are reserved by the Johnny.Decimal system, and I hope the ID is obvious. It's the very first thing you should encounter in your system, the top of the tree: <code>00.00</code>. It lives inside the system-reserved category <code>00</code>.</p>
<div class="JDBlock"> <pre>▓ 00-09 System-management area/</pre><pre>▓ └── 00 System-management category/</pre><pre>▓ └── 00.00 JDex for the system</pre><pre>▓ 10-19 Life administration/</pre><pre>▓ └── …and so on</pre><pre>__________________</pre><pre>Figure 22.00.0182N.</pre> </div>
<p>Happy with that? There's a lot going on, and it's about to get deep. Get comfortable with that before we move on.</p>
<h3 id="what-goes-in-0000">What goes in 00.00?</h3>
<p>Above, we noted how Obsidian just watches a folder full of files and lets you edit them. The screenshot (figure 22.00.0182K) shows those folders in the left pane, full of text files. Those folders look like your Johnny.Decimal system. As this is your JDex, <em>they define your system</em>. So they look something like this.</p>
<div class="JDBlock"> <pre>░ 00-09 System-management area/</pre><pre>░ └── 00 System-management category/</pre><pre>░ └── 00.00 JDex for the system.md</pre><pre>░ 10-19 Life administration/</pre><pre>░ └── 11 Me & other living things/</pre><pre>░ ├── 11.11 Birth certificate & proof of name.md</pre><pre>░ ├── 11.12 Passports, residency, & citizenship.md</pre><pre>░ └── …and so on</pre><pre>__________________</pre><pre>Figure 22.00.0182P.</pre> </div>
<p>No, I didn't duplicate the previous figure by accident. Note the subtle difference from figure 22.00.0182M: now the IDs are Markdown (.md) files, which is what Obsidian will display in the right pane.</p>
<p>So if we stitch these two diagrams together, this is what your filesystem looks like.<sup><a href="#user-content-fn-obsidian-jdex" id="user-content-fnref-obsidian-jdex" data-footnote-ref="" aria-describedby="footnote-label">5</a></sup></p>
<div class="JDBlock"> <pre>▓ 00-09 System-management area/</pre><pre>▓ └── 00 System-management category/</pre><pre>▓ └── 00.00 JDex for the system/</pre><pre>░ ├── 00-09 System-management area/</pre><pre>░ │ └── 00 System-management category/</pre><pre>░ │ └── 00.00 JDex for the system.md</pre><pre>░ └── 10-19 Life administration/</pre><pre>░ └── 11 Me & other living things/</pre><pre>░ ├── 11.11 Birth certificate</pre><pre>░ │ & proof of name.md</pre><pre>░ └── 11.12 Passports, residency,</pre><pre>░ & citizenship.md</pre><pre>▓ 10-19 Life administration/</pre><pre>▓ └── 11 Me & other living things/</pre><pre>▓ ├── 11.11 Birth certificate & proof of name</pre><pre>▓ ├── 11.12 Passports, residency, & citizenship</pre><pre>▓ └── …and so on</pre><pre>__________________</pre><pre>Figure 22.00.0182R.</pre> </div>
<p>Be <em>really</em> comfortable with that before we continue. At first glance this looks bonkers. But when you understand that <code>00.00</code> is a Johnny.Decimal ID that just happens to contain a folder structure that mirrors the overall structure … it's fine. And you're never spending any time in there yourself: let Obsidian manage it.</p>
<h3 id="this-is-the-partially-nested-pattern">This is the 'partially nested' pattern</h3>
<p>When you download your JDex files from JDHQ, there are a handful of options for Obsidian. This is the 'partially nested' pattern, in that the ID files are nested within an area/category structure. Obsidian shows this structure in the left pane.</p>
<p>There's an alternative 'flat' structure, in which those Markdown files aren't nested within an area/category structure. Some people just prefer that. I'll leave it as an exercise to the reader to imagine how this looks in your filesystem. (You can <a href="https://jdhq.johnnydecimal.com/support/settings-downloads/life-admin-downloads/">download these files from JDHQ</a> as many times as you like: try it out. Note that you'll need to <a href="https://jdhq.johnnydecimal.com/support/settings-downloads/life-admin-settings/">select Obsidian as your JDex app</a> first. Both links require a JDHQ account.)</p>
<p>Let's place a dot on the diagram that represents these patterns. We're not concerned with whether we're storing data in our JDex or not, so we'll stick it in the middle.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="The quadrant chart now has a single data point, horizontally centered, vertically in the top half, labelled 'Obsidian files saved at 00.00'." class=" auto-dark astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182S-Quadrant_4--0-cx-465x465@2x.png" width="465" height="465"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182S. Obsidian on the quadrant chart.</figcaption> </picture>
<h3 id="the-fully-nested-pattern">The 'fully nested' pattern</h3>
<p>In the scenario just described, your JDex files were <em>separate</em> from the rest of your files: they're all saved at <code>00.00</code> while the rest of your stuff is below.</p>
<p>What if you didn't want to do this? What if you wanted to merge these two structures -- JDex and filesystem -- so that there was only one? This is possible, of course, and we call it the 'fully nested' pattern.</p>
<p>In this pattern, folder <code>00.00</code> goes unused.<sup><a href="#user-content-fn-unused" id="user-content-fnref-unused" data-footnote-ref="" aria-describedby="footnote-label">6</a></sup> Instead, each of the Markdown files that are your JDex entries are scattered through your filesystem. Again, I've used the dark and light blocks to represent which components come from the original diagrams.</p>
<div class="JDBlock"> <pre>▓ 00-09 System-management area/</pre><pre>▓ └── 00 System-management category/</pre><pre>▓ └── 00.00 JDex for this system/</pre><pre>░ └── 00.00 JDex for this system.md</pre><pre>▓ 10-19 Life administration/</pre><pre>▓ └── 11 Me & other living things/</pre><pre>▓ ├── 11.11 Birth certificate & proof of name/</pre><pre>░ │ ├── 11.11 Birth certificate</pre><pre>░ │ │ & proof of name.md</pre><pre>▓ │ └── Photograph of birth certificate.jpg</pre><pre>▓ ├── 11.12 Passports, residency, & citizenship/</pre><pre>░ │ ├── 11.12 Passports, residency,</pre><pre>░ │ │ & citizenship.md</pre><pre>▓ │ └── Passport application.pdf</pre><pre>▓ └── …and so on</pre><pre>__________________</pre><pre>Figure 22.00.0182T.</pre> </div>
<p>On the surface, this feels like a good idea. Why <em>wouldn't</em> you want it all integrated? But me and many others have tried this and the universal consensus is that this doesn't work.</p>
<p>The point of this article is to explain these methods, not to tell you why one of them is worse than the others. So, just briefly:</p>
<ul>
<li>The clean separation of JDex from filesystem is a nice mental separation. It reinforces your JDex as being the more important thing. Merging them breaks that.</li>
<li>Previously, you were pointing Obsidian at a folder full of tiny text files. Now, you're pointing it at your entire filesystem. There might be terabytes of data in there. This can slow it down significantly.</li>
<li>You're no longer able to selectively synchronise folders because <em>the folder is the JDex entry</em>. This was the killer blow for me.</li>
</ul>
<p>So you probably shouldn't do this. For completion, let's add it to the diagram.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="We've added 'Obsidian files fully nested' _above_ 'Obsidian files saved at 00.00'." class=" auto-dark astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182U-Quadrant_5--0-cx-465x465@2x.png" width="465" height="465"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182U. Two Obsidian options.</figcaption> </picture>
<p>I've placed this item nearer the top of the chart as your JDex files are <em>more</em> 'in your filesystem' using this method than they were with the previous method.</p>
<h3 id="core-concepts-finished">Core concepts finished</h3>
<p>That's it for core concepts. In the next section, let's fill out the diagram with some examples.</p>
<h2 id="examples">Examples</h2>
<p>There are a handful of scenarios that we already understand. The diagram's getting busy so I'll extract some meaning to a table.</p>
<picture class="JDImage6 astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (min-width: 600px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: light) and (max-width: 599px)" class="astro-3zw7efbj"> <source media="(prefers-color-scheme: dark) and (max-width: 599px)" class="astro-3zw7efbj"> <img alt="There are a bunch more data points as described in the table below." class=" auto-dark astro-3zw7efbj" loading="lazy" src="https://johnnydecimal.com/img/v6/22.00.0182V-Quadrant_6--0-cx-465x465@2x.png" width="465" height="465"> <figcaption class="astro-3zw7efbj">Figure 22.00.0182V. I honestly thought I was going to run out of letters for the captions on this one. Close call.</figcaption> </picture>
<table><thead><tr><th></th><th>Data stored</th><th>JDex stored</th></tr></thead><tbody><tr><td>Obsidian 1</td><td>in JDex</td><td>'fully nested'</td></tr><tr><td>Obsidian 2</td><td>in JDex</td><td>'partially nested'</td></tr><tr><td>Obsidian 3</td><td>externally</td><td>'fully nested'</td></tr><tr><td>Obsidian 4</td><td>externally</td><td>'partially nested'</td></tr><tr><td>Bear 1</td><td>in JDex</td><td>managed by Bear</td></tr><tr><td>Bear 2</td><td>externally</td><td>managed by Bear</td></tr><tr><td>Excel</td><td>externally</td><td>as an .xlsx in your filesystem</td></tr><tr><td>Google Sheets</td><td>externally</td><td>in your Google Drive</td></tr><tr><td>Notion</td><td>within Notion</td><td>by Notion in their cloud</td></tr><tr><td>SQLite database</td><td>within the database</td><td>as a .db file in your filesystem</td></tr><tr><td>Airtable</td><td>externally</td><td>by Airtable in their cloud</td></tr></tbody></table>
<h3 id="nit-picky-points">Nit-picky points</h3>
<p>We're getting in the weeds here, but I positioned those dots carefully so we might as well explain why.</p>
<p>The left/right split isn't so interesting: you either store data in your JDex, or you don't. Your choice here might be limited by the method you use to store your JDex. As we've already said, a spreadsheet is a terrible place to keep long-form notes; spreadsheets tend towards the right edge.</p>
<p>If you use a database like Notion, it's up to you. In this diagram I've designed a Notion where you <em>do</em> keep data there. Given Notion's power, this feels like a realistic scenario. But you could just have well designed a pure JDex-only database and stored all data externally.</p>
<p><em>Where</em> the files are, on the vertical axis, is a touch more interesting. Google Sheets is in the lower half while Excel is in the upper because the Excel sheet is a file that you need to manage, and the Google Sheet exclusively lives in your Google Drive.</p>
<p>That said, you do still need to specify <em>where</em> in your Google Drive the file exists. You still need to file it somewhere, even if that somewhere happens to be in the cloud. Which is why Google Drive is above Airtable, an online database. With Airtable there is no consideration at all 'where' your database is stored. You don't get a folder structure that you have to 'file your database' in. (Other than a rudimentary dashboard that you can rearrange.) Your database is just <em>at Airtable</em>.</p>
<p>Similarly, Notion is at the bottom, because all of your stuff is in the Notion cloud. Conversely you might prefer to build yourself a SQLite database which <em>is</em> now a file that you need to manage. As we now know, that database should be stored at <code>00.00</code>.</p>
<h3 id="thatll-do">That'll do</h3>
<p>I wrote this article to set up a framework that I can use in the future; a diagram into which I can slot more scenarios. This isn't meant to be comprehensive. There are a thousand scenarios that aren't included here.</p>
<hr>
<p><em>100% human. 0% AI. Always.</em></p>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-library">
<p>You might be thinking, 'that's not how I use my library'. But when you go to the library you're likely <em>browsing</em> the shelves. You don't know what you're looking for. That's a different behaviour from going to a reference library and recalling a specific book, which is the analogy here. <a href="#user-content-fnref-library" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-excel">
<p>A spreadsheet provides a nice way to think about your metadata. If each row is an ID, your columns store metadata. It's easy to see how you'd have one standard column for <code>Location</code>, and that adding another column for <code>Where is it?</code> is obviously silly. Columns define the keys of our key/value pairs. <a href="#user-content-fnref-excel" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-not-a-backup">
<p>With the caveat that cloud storage is <em>not a backup</em>. See my mini-series on <a href="https://johnnydecimal.com/20-29-communication/22-blog/22.00.0101-my-backup-strategy#in-this-series">data, storage, and backups</a>. <a href="#user-content-fnref-not-a-backup" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-export">
<p>If you use these apps, an important consideration becomes 'lock-in'. How easy is it to export your data, if you choose? Bear makes this easy. Others might make it harder, or it might not be practical. Craft and Notion, for example, are database apps. You can't just export a database to a bunch of text files and expect it to make sense. <a href="#user-content-fnref-export" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-obsidian-jdex">
<p>Actually, I add <em>another</em> folder below <code>00.00</code> that contains both of the folders <code>00-09</code> and <code>10-19</code>. This is because Obsidian doesn't allow you to 'rename' a vault: the vault name is just the name of the folder of files that you have opened. In the situation shown, the vault name would be '00.00 JDex for the system'.</p>
<p>I manage multiple vaults and want a more descriptive name. My business system's folder is named 'D25 JDex': D25 is the system identifier. This then appears as the vault name. In the screenshot above (figure 22.00.0182H) you can see the vault name is 'JDex - Life Admin System'. This is how it's downloaded from JDHQ. I left this detail out of the diagram as it's not important to the fundamental concept. <a href="#user-content-fnref-obsidian-jdex" data-footnote-backref="" aria-label="Back to reference 5" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-unused">
<p>Other than to store its <em>own</em> JDex entry, as shown. <a href="#user-content-fnref-unused" data-footnote-backref="" aria-label="Back to reference 6" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>The Coherence Premium - Westenberg6981098b2d394c00012d2acf2026-02-02T22:41:04.000Z<img src="https://images.unsplash.com/photo-1550859492-d5da9d8e45f3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDM2fHxhYnN0cmFjdHxlbnwwfHx8fDE3NzAwNjQ0MjJ8MA&ixlib=rb-4.1.0&q=80&w=2000" alt="The Coherence Premium"><p>I don't necessarily believe in second brains. The notion (pun-intended) that you can offload your thinking to a perfectly organized system of notes and links has always struck me as a fantasy. The people I know who've built elaborate Notion databases or Obsidian vaults mostly end up with digital hoarding problems, where the system becomes the work. And I'm broadly skeptical of the Claude Code productivity discourse, the idea that AI tools will let you 10x your output if you prompt them correctly. (Most people using AI are producing more stuff faster without any clear sense of whether the stuff is good or consistent or even pointed in the right direction.)</p><p>But I do believe in something adjacent to both of these ideas, something that borrows from the second brain concept without the hoarding, and from AI tooling without the context-free prompting: <em>I believe in coherence as a system.</em></p><p>In 1937, the British economist Ronald Coase asked a question that seems almost embarrassingly simple: why do firms exist at all? If markets are so efficient at allocating resources, why don't we just have billions of individuals contracting with each other for every task? Why do we need these hulking organizational structures called companies?</p><p>His answer, which eventually won him a Nobel Prize, was transaction costs. It's expensive to negotiate contracts and coordinate with strangers, to monitor performance and enforce agreements. Firms exist because sometimes it's cheaper to bring activities inside an organization than to contract for them on the open market. The boundary of the firm, Coase argued, sits wherever the cost of internal coordination equals the cost of external transaction.</p><p>This was a brilliant insight in '37, but Coase couldn't have anticipated what happens when transaction costs collapse. When software eats coordination. When a single person with the right tools can do what used to require a department. When AI can execute tasks that once demanded teams of specialists.</p><p>We're in a Coasean inversion. The economics that made large firms necessary are reversing. But most people are looking at this transformation through the wrong lens. They see AI as a productivity tool, a way to do more faster. They measure success in hours saved or output multiplied, and this misses the point entirely.</p><p>The solopreneur's advantage is not solely speed, and it's certainly not "lower costs" despite what a good too many seem to think. </p><p>The advantage is coherence.</p><h2 id="what-coherence-actually-means">what coherence actually means</h2><p>When I say coherence, I mean something specific: the degree to which every part of an operation derives from the same understanding, the same model of reality and set of priorities and tradeoffs.</p><p>When you work alone, you have a problem and you understand the context because you lived it and touched it and experienced it first-hand. You make a decision based on that understanding, execute the decision, see the results, and update your understanding. The entire loop happens inside one mind.</p><p>What happens in a large organization facing the same problem? Someone identifies the problem, but they don't have authority to solve it. They write a report explaining the problem to someone who does have authority. That person reads the report, but they don't have the original context, so they ask clarifying questions. The answers come back, filtered through email or a meeting. A decision gets made, but the people who have to implement it weren't in the room. They recieve instructions that encode the decision but not the reasoning. They execute the instructions as best they understand them. The results come back through multiple layers of reporting. By the time the original decision-maker sees what happened, months have passed and the context has shifted again.</p><p>This is the basic challenge of coordination across minds. Every handoff loses information, every translation introduces drift, and every layer of abstraction moves further from ground truth.</p><p>Organizations have spent decades trying to solve this problem. They've built elaborate systems of documentation, standardized processes, metrics and KPIs, regular meetings, shared values statements, company cultures. All of these are attempts to create coherence across minds. And they all fail, in different ways and to different degrees, because they're fighting against something that won't budge: knowledge is sticky and context is lossy, and understanding doesn't transfer perfectly between humans.</p><h2 id="the-pathology-of-process-drift">the pathology of process drift</h2><p>A company starts small, with the founders doing everything themselves. They make decisions quickly because they understand everything about the business, and the business works.</p><p>The company grows and the founders can't do everything anymore. They hire people and try to transfer their understanding. But understanding doesn't transfer easily, so they also transfer processes. "This is how we do X. Use this checklist for Y. Follow these steps."</p><p>The processes work, mostly. But the new employees don't have the context that generated those processes. They don't know why step three comes before step four, and they don't know which parts are essential and which parts were arbitrary choices. So when situations arise that the process doesn't quite cover, they either follow the process rigidly and get suboptimal results, or they improvise and create inconsistency.</p><p>More growth, more employees, more processes. The processes start interacting in ways nobody anticipated. The sales process assumes certain things about the product process. The product process assumes certain things about the engineering process. When those assumptions drift out of alignment, you get friction and delays and finger-pointing.</p><p>The company responds by adding coordination mechanisms like project managers, alignment meetings, and cross-functional reviews. These help, but they also add overhead, and they create their own drift: the coordination layer develops its own processes, its own assumptions, its own information loss.</p><p>Eventually you reach a point where a significant fraction of the organization's energy goes toward internal coordination rather than actual value creation. A 2022 Microsoft study found that employees in large organizations spend over 50% of their time on internal communication and coordination. Half the payroll, dedicated to getting the organization to agree with itself.</p><h2 id="context-fragmentation">context fragmentation</h2><p>More information means the coordination problem gets worse, not better. This seems counterintuitive, because shouldn't more information make everyone more aligned?</p><p>But <em>information isn't understanding.</em> Understanding = integration, and integration happens in minds. More information means more raw material that each mind has to process differently.</p><p>A typical large organization's knowledge base is spilling over with strategy documents from last year and the year before, project postmortems from dozens of initiatives, customer research reports, competitive analyses, technical specifications, meeting notes, email threads, Slack channels, and wiki pages. </p><p>Somewhere in there (the elusive somewhere...) is everything you need to know to make a good decision.</p><p>But nobody has synthesized it all, and nobody has integrated it into a coherent model. Each person reads a fragment, interprets it through their own context, and forms their own understanding. When they discuss decisions with colleagues, they're not comparing the same mental models but rather different interpretations of different subsets of the available information.</p><p>This is context fragmentation. People don't disagree on facts; they're operating from different maps of the same territory. And because the maps are implicit, inside people's heads, nobody realizes they're not looking at the same thing.</p><p>The proliferation of AI tools in large organizations means that now each employee has their own AI assistant, trained on whatever context they happen to feed it, producing outputs that reflect their particular understanding of the situation. The AI amplifies individual perspectives rather than creating shared ones.</p><h2 id="single-player-mode-advantage">single-player mode advantage</h2><p>When you're operating alone, you have one context, one understanding, one model of your business and your market and your customers and your strategy. That model lives in your head, and it's coherent because there's only one mind maintaining it.</p><p>If // when you use AI tools, you're feeding them from that single source of truth. The AI doesn't have its own understanding that might drift from yours, and it operates within the context you provide. If you give it good context, it executes within that context. If your understanding is coherent, the AI's outputs will be coherent.</p><p>This is the inversion of the traditional organization's problem. In a large organization, you have many minds with their own contexts, trying to coordinate through AI tools that amplify their differences. As a solo operator, you have one mind with one context, using AI tools to execute within that coherent frame.</p><p>The AI handles the execution at scale while you maintain the coherence. This division of labor plays to the strengths of each party: humans are good at integration and judgment, while AI is good at execution and volume. The solo operator with AI gets the benefits of scale without the costs of coordination.</p><p>But this only works if you actually maintain coherence. </p><p>If you're using AI to do random shit faster, you're not capturing the advantage. The advantage comes from having a tight operating model that the AI operates within.</p><h2 id="the-coherence-stack">the coherence stack</h2><p>Think of it as a stack with four layers, each feeding the one below it.</p><pre><code>┌─────────────────────────────────────┐
│ MIND LAYER (You) │
│ Understanding, judgment, strategy │
│ The source of coherence │
└─────────────────┬───────────────────┘
│ feeds
▼
┌─────────────────────────────────────┐
│ CONTEXT LAYER │
│ Operating model, constraints │
│ Voice guidelines, decision logs │
└─────────────────┬───────────────────┘
│ constrains
▼
┌─────────────────────────────────────┐
│ EXECUTION LAYER (AI) │
│ Content, code, research, analysis │
│ Customer responses at scale │
└─────────────────┬───────────────────┘
│ produces
▼
┌─────────────────────────────────────┐
│ OUTPUT LAYER │
│ Coherence-checked artifacts │
│ What actually ships │
└─────────────────┬───────────────────┘
│ feedback
└────────────────────► Mind Layer
</code></pre><p>At the top is the mind layer, which is you: your understanding, your judgment, your integrated model of the business. This layer can't be automated or delegated, and it's the source of coherence.</p><p>Below that is the context layer, where you externalize your understanding into documents that AI tools can consume. Your operating model, your constraints and tradeoffs, your voice guidelines, your decision history. This layer translates what's in your head into something machines can work with.</p><p>Below that is the execution layer, where AI operates. Content generation, research, analysis, code, customer responses. The AI works within the constraints provided by the context layer, producing outputs at scale.</p><p>At the bottom is the output layer, which is what actually ships. But nothing reaches this layer without passing through a coherence check: does this output reflect my model? Would I have produced something like this? Does it fit with everything else?</p><p>The stack only works if information flows correctly. The mind layer feeds the context layer through deliberate documentation, the context layer constrains the execution layer through careful prompting, and the output layer feeds back to the mind layer through review, which sometimes triggers updates to your understanding.</p><p>Most people using AI skip the context layer entirely. They go straight from a vague intention to an AI prompt to shipped output. This is how you get drift // how you end up with an operation that feels incoherent, where different pieces don't quite fit together, where customers sense something is off even if they can't articulate what.</p><h2 id="building-your-context-layer">building your context layer</h2><p>The context layer is where the work happens. It's the translation mechanism between your understanding and AI execution. Get this right and coherence becomes automatic; get it wrong and you're constantly fighting drift.</p><p>Start with your operating model - a working description of how your business actually functions. </p><p>I structure mine around five questions.</p><pre><code>┌────────────────────────────────────────────────────────┐
│ OPERATING MODEL │
│ (Five Core Questions) │
├────────────────────────────────────────────────────────┤
│ │
│ 1. PROBLEM & AUDIENCE │
│ What problem do I solve, for whom specifically? │
│ Not demographics. The person in the moment. │
│ │
│ 2. THESIS │
│ Why does my approach work? │
│ The real theory, not marketing language. │
│ │
│ 3. TRADEOFFS │
│ What am I optimizing for, at what expense? │
│ Make the choices explicit. │
│ │
│ 4. BOUNDARIES │
│ What do I explicitly not do? │
│ The boundaries define the shape. │
│ │
│ 5. VOICE │
│ How do I actually sound? │
│ Words I use. Words I avoid. Stance toward reader. │
│ │
└────────────────────────────────────────────────────────┘
</code></pre><ul><li>What problem do I solve, and for whom specifically? Steer clear of demographics; you need a description of the person in the moment they need what I offer. What are they trying to do, and what's getting in their way?</li><li>What's my actual thesis for why my approach works? Why does my solution address the problem better than alternatives?</li><li>What are the core tradeoffs I've chosen? Every business is a bundle of tradeoffs, and I'm optimizing for X at the expense of Y. Making these explicit prevents drift, because when a new opportunity arises, I can check it against my tradeoffs rather than deciding ad hoc.</li><li>What do I explicitly not do? This is more useful than describing what you do, because the boundaries define the shape.</li><li>How do I sound? What words do I use, what words do I avoid, what's my stance toward the reader? Capturing this helps AI maintain consistency across outputs.</li></ul><p>This document should be short enough to include in AI prompts. If it's longer than a page, you haven't distilled it enough. The goal is compression without loss of generative power.</p><p>Next, build your constraints file. These are the decision-making rails that keep outputs on track. I think of them as principles // functional rules that generate answers.</p><p>For example: "When choosing between comprehensive and focused, choose focused. Our readers are busy and will bounce if they don't get value in the first paragraph." That's a constraint that actually constrains, telling the AI (and me) how to resolve a common tradeoff.</p><p>Include examples. Point to a piece you wrote that exemplifies the voice, and one that doesn't. Concrete examples communicate more than abstract descriptions.</p><p>Finally, maintain a decision log. When you make a significant choice, write down what you decided and why. This creates institutional memory for a one-person institution. When similar situations arise later, you (or your AI tools) can refrence how you've handled them before. This prevents the common failure mode where you decide the same question differently each time because you forgot your previous reasoning.</p><h2 id="a-coherence-check">a coherence check</h2><p>Every output that ships should pass through a coherence check. This can be quick, but it can't be skipped.</p><pre><code>┌────────────────────────────────────────────────────────┐
│ COHERENCE CHECK │
├────────────────────────────────────────────────────────┤
│ □ Does this sound like one person wrote it? │
│ □ Would I explain it this way? │
│ □ Does it reflect my specific tradeoffs? │
│ □ Could a competitor produce this? (Should be no) │
│ □ Does it fit with everything else I've shipped? │
│ │
└────────────────────────────────────────────────────────┘
</code></pre><p>The questions:</p><ul><li>Does this sound like one person wrote it? AI tends toward a certain homogeneity, and if an output could have been produced by anyone, it's not coherent with my operation.</li><li>Would I explain it this way? The same framing, the examples, the emphasis? If I'd approach it differently, the output needs revision or I need to update my context documents.</li><li>Does it show // hold my specific tradeoffs? If I've chosen focused over comprehensive, is this output focused? If I've chosen accessible over technical, is this accessible?</li><li>Could a competitor produce this? If the answer is yes, the output isn't coherent enough. It's not distinctive and doesn't come from my particular understanding.</li><li>Does it fit with everything else I've shipped? Coherence is cumulative, and each output should feel like it belongs with the others. If this piece would feel out of place next to my other work, something's wrong.</li></ul><p>You can automate part of this. Feed your AI tool your recent outputs and ask it to compare a new draft against them, flagging inconsistencies. But the final judgment has to be yours. You're the source of coherence, and the check is really asking: does this feel like mine?</p><h2 id="anti-patterns-that-break-coherence">anti-patterns that break coherence</h2><p>I've watched myself and others struggle with this. </p><p>A few failure modes reliably produce drift:</p><pre><code>┌────────────────────────────────────────────────────────┐
│ COHERENCE ANTI-PATTERNS │
├────────────────────────────────────────────────────────┤
│ │
│ CONTEXT STARVATION │
│ └─► AI works from generic training, not your model │
│ │
│ OUTPUT ACCUMULATION │
│ └─► Shipping without review; deviations compound │
│ │
│ MODEL STALENESS │
│ └─► Understanding evolves, documents don't │
│ │
│ FRAGMENTED TOOLING │
│ └─► Different tools, different contexts, drift │
│ │
│ DECISION AMNESIA │
│ └─► No rationale logged; inconsistent future choices │
│ │
└────────────────────────────────────────────────────────┘
</code></pre><ul><li>Context starvation is the most common. You ask AI to do something without feeding it your operating model, your constraints, your voice. The AI does its best, but it's working from generic training rather than your specific understanding. The output is competent but not coherent.</li><li>Output accumulation is context starvation's downstream consequence. You ship AI outputs without proper review, and each one is slightly off from your model. The deviations accumulate. After a few months, your operation no longer reflects your understanding because most of what you've shipped wasn't actually generated from your understanding.</li><li>Model staleness happens when your understanding evolves but your context documents don't. You learn something that changes how you think about the business, but you don't propagate that update to your operating model or constraints file. Now your AI tools are working from an outdated picture.</li><li>Fragmented tooling = using different AI tools with different contexts. You use one tool for writing and another for code and another for research, and each has different context, different prompts, different understandings of what you're doing. The outputs don't cohere because they're not coming from the same source.</li><li>Decision amnesia = making choices without recording the reasoning. You decide something, move on, and three months later face a similar choice with no memory of how you handled it before. You decide differently this time. Now you have inconsistent decisions in your history, and any AI tool referencing your past work will find contradictions.</li></ul><h2 id="the-fragmentation-audit">the fragmentation audit</h2><p>You should audit your operation for coherence as often as possible. I do this monthly, AI tools or not, AI be damned, but the frequency matters less than doing it at all.</p><p>Pull your last twenty or thirty outputs, whether blog posts, emails, product updates, or whatever you've shipped. Lay them out and look for the implied beliefs and positions in each. What does this piece assume about the reader? What does it prioritize, and what stance does it take?</p><p>You're looking for drift: places where piece A assumes one thing and piece B assumes something different, places where your voice shifted without intention, places where you contradicted yourself purely because you genuinely forgot what you'd said before.</p><p>When you find inconsistencies, you have two options. Either reconcile them by updating your model (maybe you actually did change your mind, and the recent piece reflects your current thinking), or flag them as errors and correct going forward.</p><p>This audit also reveals context layer gaps. If you keep finding drift in a particular area, your context documents probably don't cover that area well enough. Add constraints, add examples, make the implicit explicit.</p><h2 id="why-this-beats-scale">why this beats scale</h2><p>Large organizations have obvious advantages. They have capital, they have brand recognition, distribution, expertise, redundancy, Las Vegas conferences etc. A solo operator can't compete on those dimensions.</p><p>But think what those advantages actually buy. Capital lets you hire more people, and more people means more coordination overhead and context fragmentation. Brand recognition helps customers find you, but it doesn't help you serve them coherently. Distribution gets your product to more places, but each touchpoint introduces opportunities for inconsistency. Expertise is great, but experts in different domains don't automaticaly share mental models.</p><p>Meanwhile, the solo operator with a coherent system has advantages that don't show up on traditional metrics. Every customer interaction comes from the same understanding, and every piece of content reflects the same perspective. Every product decision follows from the same model. The operation feels like one thing, because it is one thing.</p><p>Customers experience this as quality, even if they can't articulate why. They sense that someone understands what they're doing and why, and they don't encounter the cognitive dissonance of dealing with an organization that can't agree with itself.</p><p>The dynamic that makes this sustainable is that <em>coherence compounds</em>. Each decision you make within your model reinforces the model, and each output that reflects your understanding strengthens your position. Your operation becomes more legible over time, both to you and to your customers. Meanwhile, large organizations' incoherence also compounds, with each misalignment creating more misalignment and each process drift opening space for more drift.</p><p>The gap widens.</p><p>The coherence advantage works best in domains where the value comes from understanding rather than from physical or regulatory scale. Knowledge work, creative work, advisory work, software, content, education, consulting. These are domains where a coherent perspective can outcompete a fragmented organization's superior resources.</p><p>And the opportunity is unique: the technology exists to operate at scale while maintaining the coherence of a single mind. The window is open because large organizations haven't figured out how to respond. Their answer to AI so far has been to give everyone AI tools and hope for productivity gains, which accelerates their fragmentation...</p><h2 id="the-coherence-moat">the coherence moat</h2><p>Scale used to be the moat. You built a big organization with lots of resources, and the sheer weight of your operation protected you from smaller competitors. Transaction costs made it hard for anyone to replicate what you'd built.</p><p>But transaction costs are collapsing. The activities that used to require organizations can increasingly be performed by individuals with the right tools.</p><p>The Coasean logic that justified large firms is weakening.</p><p>If there is a new moat (and I'll admit, that's a big "if") it probably looks like coherence; the ability to operate as one mind, one understanding, one model, even as you execute at scale. Large organizations can't have this because they're composed of many minds. Solo operators can have it by default, if they're deliberate about maintaining it.</p><p>The solo operator who builds a coherent system and lets AI execute within it has an advantage that doesn't need venture capital, doesn't need hiring, and doesn't ask for the whole apparatus of organizational scaling.</p><p>Scale breaks coherence. Coherence is the moat.</p>Book Review: The Voyage of the Space Beagle by Alfred Elton Van Vogt ★★☆☆☆ - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=665422026-02-02T12:34:39.000Z<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/The_Voyage_of_the_Space_Beagle_book_front_cover.jpg" alt="Book cover featuring a large alien on a scary planet." width="250" height="391" class="alignleft size-full wp-image-66544"/>
<p>This is Star Trek <em>before</em> Star Trek. It is Alien long before Alien. It is the template for so much modern science fiction. What it is <em>not</em> is particularly good.</p>
<p>I don't intend to dump on the classics (and this is undoubtedly a classic) but 1950s sci-fi takes place in an almost alien media environment. Even if you ignore the anachronisms (<a href="https://shkspr.mobi/blog/2012/05/why-cant-red-dwarf-predict-the-future/">like having to develop film in order to see photographs</a>) and the archaic language (lots of vibrators being used against a big pussy) it is hard to get over how unconvincing it all is.</p>
<p>In the first story, the crew of the Space Beagle find an alien monster. It probably killed one of them. They bring it aboard and just let it lounge about in the library! Yes, all the science is fun, and the "competency porn" of the professional crew is suitably heroic, but the characters and their motivations are frequently bizarre. It is only through the complete absence of girls (urgh!) that there's no interstellar sexism.</p>
<p>The protagonist, Grosvenor, is a cipher for every geeky kid who ever felt he was smarter than everyone else. He is a sneering, taciturn, and deeply unpleasant character. When given the opportunity, he relishes the chance to become dictator.</p>
<p>Because the book started life as a set of short stories, it works reasonably well as a "monster of the week" show. It is episodic, with well-placed cliffhangers. The science is <em>very</em> sciency with some excellent speculative elements. You've got aliens planting eggs in people (like Alien) and a ship's engineer who says "Nooo! The walls couldn't stand it. They'd melt." (like Scotty) and any number of concepts you'll recognise from your favourite TV shows.</p>
<p>The obsession with hypnotism and mind-control feels a bit icky, especially when understood in association with the author's dalliance with the pseudoscience of Dianetics.</p>
<p>The language (when not steeped in 1950's idiomatic phrasing) can verge on the poetic. Every story includes a chapter or two from the alien's viewpoint. They are deliciously weird and elevate this book beyond what might be a slightly forgettable slice of sci-fi.</p>
<p>It is absolutely worth reading - if only to see how influential it has been - but it can be a bit of a weird slog at times.</p>
IndieWeb Book Club: The Art of Explanation - James' Coffee Bloghttps://jamesg.blog/2026/02/01/the-art-of-explanation/2026-02-01T19:36:12.000Z
<p>I am hosting the <a href="https://indieweb.org/IndieWeb_Book_Club">IndieWeb Book Club</a> for this month, in which everyone interested is invited to read and write a blog post about <em>The Art of Explanation: How to Communicate with Clarity and Confidence</em> [<a href="https://www.goodreads.com/book/show/64631477-the-art-of-explanation">Goodreads link</a>]. The book was authored by Ros Atkins, a BBC journalist whose career has spanned radio on the BBC World Service and television on BBC News.</p><p>I read this book toward the end of last year and loved that the advice given was tactical, engaging, and interspersed with stories. I’d highly recommend it to anyone interested in refining their communication or explanation skills.</p><p><em>The Art of Explanation</em> is quite a long read, and may not be easy to fit into a month. I’d highly recommend reading the introduction and a chapter or two that looks most interesting to you – this will be enough to both give you a feel for the book, (hopefully) many insights, and what you need to write a blog post for the Carnival. If you have time and the motivation, keep reading! I wanted to add the caveat that you don’t need to finish the book because I know how hard it can be to finish a book in a month. I still want you to feel encouraged to pick up this book and read a bit!</p><p>If you read any of <em>The Art of Explanation</em> and write a blog post about the book this month, please email me at readers [at] jamesg [dot] blog and I will add your submission to the round-up at the end of the month.</p>
Will They Inherit Our Blogs? - Kev Quirkhttps://kevquirk.com/blog/will-they-inherit-our-blogs/2026-02-01T18:45:00.000Z
<p style="font-size: 1.2em;">I've been thinking about how this site may be able to live on after I'm gone. Maybe it could become a family heirloom?</p>
<p>I’ve thought about this topic more generally <a href="https://kevquirk.com/blog/what-happens-when-were-gone/">before</a>, but this one is specifically about blogging.</p>
<p>This blog is <em>by far</em> the hobby I have sunk the most time into over the last 13-ish years, and I’d like to think I’ll continue as I head from middle age, to old age. Let’s say I live until I’m 80, I will have spent over 50 years of my time on this earth writing content here at <code class="language-plaintext highlighter-rouge">kevquirk.com</code>.</p>
<p>I don’t want all the hard work to disappear in a puff of smoke once I snuff it, so I’ve been thinking. <em>Could this blog become a family heirloom?</em>. Could I pass this site on to one (or both) of my sons and have them continue to write here?</p>
<p>They wouldn’t even need to continue to use <code class="language-plaintext highlighter-rouge">kevquirk.com</code>. They could write on their own domain(s), and just redirect this one.</p>
<p>I like to think that many of the other long-time bloggers out there might want the same. Maybe one day it’ll be normal to leave our blogs to our kids?</p>
<h2 id="a-question-worth-asking">A question worth asking</h2>
<p>I do think it’s something we should consider. I’m part of the first generation that grew up online, and most of us are still very much alive. But as time marches on, more of us are going to leave behind these digital epitaphs.</p>
<p>I’d love it if my sons took up blogging when they’re old enough to (that, and riding motorbikes!). But they’re their own people, and may not want to. If that’s the case, I just hope they’ll agree to keep my waffle online for a little while once I’m gone. 🤷🏻♂️</p>
<div class="email-hidden">
<hr>
<p>Thanks for reading this post via RSS. RSS is great, and you're great for using it. ❤️</p>
<p>
You can <a href="mailto:72ja@qrk.one?subject=Will They Inherit Our Blogs?">reply to this post by email</a>, or <a href="https://kevquirk.com/blog/will-they-inherit-our-blogs/#comments">leave a comment</a>.
</p>
</div>
Vanguard - The Government Project to get British Businesses to use the Internet - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=631222026-02-01T12:34:10.000Z<p>Email isn't an obvious business benefit. Imagine it is the early 1980s and you need to communicate with people across the country. A first-class letter <a href="https://gbps.org.uk/information/rates/inland/letters-1968-2006.php">will cost you 17p</a> - about 60p in <a href="https://www.bankofengland.co.uk/monetary-policy/inflation/inflation-calculator">today's money</a>. The letter will be delivered the next day and you'll have your answer back the day after.</p>
<p>By contrast, a single computer terminal was likely to set you back <a href="https://nosher.net/archives/computers/adve_045">around £3,000</a> - and that's before you take into account message transmission costs. That's roughly the same price as sending over 8,000 letters. Is that a sensible investment for the 1980's businessman?</p>
<p>In 1986, British Telecom started producing "The Communications Programme" which was "a new video magazine produced exclusively for the top communications people in the UK's largest organisations".</p>
<p>The show was distributed on video-tape and the <a href="https://btarchives.access.preservica.com/?s=&hh_cmis_filter=calm.CalmSeries%2FThe+Communications+Programme&saved_filters=calm.CalmSeries%2FThe+Communications+Programme">archived shows</a> are genuinely fascinating. They're a mixture of business reporting, thinly veiled advertorials, and a glance at the future of digital services.</p>
<p>Buried in the middle of <a href="https://btarchives.access.preservica.com/uncategorized/IO_674807ef-9ac1-4658-a6e8-86691a797d8b/">episode 4</a> is this advert from the Department of Trade and Industry.</p>
<video controls="" src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/vanguard.mp4">
<track default="" kind="captions" src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/vanguard.vtt" srclang="en"/>
</video>
<p>There's very little online information about the "Vanguard Project" - it was a <a href="https://doi.org/10.1016/0268-4012(88)90017-5">VADS initiative</a> (Value Added Data Services) run by DTI, BT, IBM, INS, ISTEL, and FASTRAK. Some of those acronyms survive, some don't!</p>
<p>Its aim was to promote awareness of EDI and its potential for the United Kingdom.</p>
<blockquote><p>In 1986 the Department of Trade and Industry launched a project called Vanguard to promote the development of this kind of service in 10 different sectors including construction, educational supplies and wholesale food distribution. The major VADS suppliers (BT, IBM, INS, Istel and the Midland Bank) in the UK were heavily involved in the project from the beginning.</p>
<p><cite><a href="https://www.google.co.uk/books/edition/Information_Sources_in_Information_Techn/0hYjAAAAQBAJ?hl=en&gbpv=0">Information Sources in Information Technology</a></cite></p></blockquote>
<p>What's "EDI"?</p>
<blockquote><p>Electronic Data Interchange.</p>
<p><a href="https://dspace.lib.cranfield.ac.uk/server/api/core/bitstreams/0973a70e-db1b-4fed-b84b-931aa86602cc/content">A means of transferring data between co-operating enterprises without having to print it out on one computer and key it into another. Requires agreement about standards (proprietary or otherwise).</a></p></blockquote>
<p>Did it work? Well, that's hard to say!</p>
<p>There's a paper from 1989 called <a href="https://dspace.lib.cranfield.ac.uk/server/api/core/bitstreams/d218650c-f50f-4627-aff7-3cf9141ee2bb/content">Survey of Electronic Data Interchange Users and Service Providers in the UK</a>. It dives into the then current challenges of getting British businesses to adopt EDI.</p>
<p>It quotes <a href="https://en.wikipedia.org/wiki/John_Harvey-Jones">Sir John Harvey-Jones</a> saying that most people running companies were:</p>
<blockquote><p>…old people like me not familiar with the technological possibilities! We have great difficulty in making imaginative jumps to see the way in which the whole of our business can be reorganised, revitalised, set up in totally new ways, releasing energy and cost and putting us into the pole position. I can see abundant evidence that the full benefits of EDI will only be reaped by the companies where the Chief Executives is seized with enthusiasm for the potential prize he can grasp.</p></blockquote>
<p>Which still seems true today! Although over-enthusiasm has led us to a weird AI-in-everything future.</p>
<p>The paper doesn't talk about Vanguard specifically, although it does have this rather cute diagram adapted from one of its reports:</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/Vanguard.webp" alt="Vague graph showing how adopting technologies is beneficial." width="2048" height="1638" class="aligncenter size-full wp-image-63127"/>
<p>Not quite the Gartner Hype Cycle!</p>
<p>The paper concludes that:</p>
<blockquote><p>Unfortunately the zealots of EDI tend to be unable to ‘sell’ the benefits to management in most companies, and this is not helped by the way that many companies have been forced to trade electronically. Management tends to think that EDI is about computers, and because they think that computers are technical they abdicate responsibility with the cry of ‘its all too difficult’. This must be wrong. It is up to those who understand EDI to learn how to talk to management, and it is up to management to understand that not only is EDI not about technology, but even if it was it is still their responsibility.</p></blockquote>
<p>Again, true as it ever was!</p>
<p>Nestled in the bibliography is this tantalising list of publications from the now-defunct Her Majesty's Stationery Office:</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/bibliography.webp" alt="List of books." width="1800" height="1346" class="aligncenter size-full wp-image-63128"/>
<p>None of which appear to be online, although <a href="https://bll01.primo.exlibrisgroup.com/discovery/fulldisplay?docid=alma990071197720109251&context=L&vid=44BL_INST:BLL01&lang=en&search_scope=BL_Available&adaptor=Local%20Search%20Engine&tab=BL_Available&query=any,contains,0115139958&sortby=title&facet=frbrgroupid,include,9020552068280143198&offset=0">a few are in The British Library</a> - and a few more <a href="https://www.google.co.uk/books/edition/Value_added_and_Data_Services_Interworki/poEfAQAAIAAJ?hl=en&gbpv=1&bsq=vanguard&dq=The%20Use%20of%20VADS%20for%20the%20Aero%20Industry&printsec=frontcover">available on Google Books</a></p>
<p>The state <a href="https://hansard.parliament.uk/Commons/1988-03-31/debates/b4a366bd-f3c1-4855-8cc0-09ff0d1f590b/ConsultancyContracts">awarded several contracts for Vanguard</a> - most of which seemed to be in the training space. Here's what <a href="https://archive.org/details/edihandbooktradi0000unse">The EDI handbook said about it</a>:</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/10/vanguard.webp" alt="To get the awareness-raising activity of VANGUARD off to a quick start, an offer of up to two days of free consultancy in the basic issues surrounding value added and data services was made to chairmen and managing directors in 10,000 medium sized companies. Some 2,000 responses were received expressing interest in learning more about VANGUARD and over 800 consultancy sessions have so far been taken up with leading technology consultants Langton, Logic, Coopers S. Lybrand, PACITL, Peat Marwick Mitchell, CAP and Scicon. All of the consultants conducting these sessions have themselves passed through a two day training course organised for VANGUARD and conveying the message that value added and data services could have significant economic and strategic benefits for those firms. Later this year, beginning in June in the South West and then moving around the country, there will be a series of VANGUARD conferences, workshops and seminars, designed to offer senior management and also lower tiers of management an opportunity to hear about value added and data services from existing users and from experts on the economics and mechanics of getting started in their use. All advice offered under the VANGUARD initiative is intended to be impartial. However, it is to be hoped that suppliers of value added and data services will sieze the opportunity created by VANGUARD through its awareness raising activity to increase, in parallel, their own awareness and promotional efforts to help potential users become more familiar with their offerings. " width="760" height="681" class="aligncenter size-full wp-image-63428"/>
<p>(My thanks to <a href="https://mas.to/@guardeddon/115134134399462585">Don Thompson</a>, <a href="https://bsky.app/profile/owenboswarva.bsky.social/post/3lxu4kxdvek2a">Owen Boswarva</a>, and <a href="https://wiki.london.hackspace.org.uk/view/User:Ms7821">Ms7821</a> for digging out some of those references.)</p>
<p>Did it work? By the time I entered the workforce in the 1990s, it seemed like every desk had a computer. Although the Internet was in its infancy, email and electronic ordering was a normal part of business. The various proto-Internet protocols were still around, but were quickly being replaced.</p>
<p>A thesis published in 1991 asked an important question:</p>
<blockquote><p>why should a non-interventionist Government as Thatchers become directly involved in developing the market and working together with private companies whose normal aim is to increase market share at the expense of their competitors rather, than cooperate with them?</p>
<p><cite><a href="https://doras.dcu.ie/19498/1/Michael_Giblin_20130729115356.pdf">The impact of Electronic data interchange on Irish foreign trade and transport</a></cite></p></blockquote>
<p><a href="https://en.wikipedia.org/wiki/Metcalfe%27s_law">Metcalfe's Law</a> tells us that there is no value being the only business on a network. It simply isn't rational to invest in connecting to a data service that no-one else is on. But the value of that network increases as more people and businesses get connected. If you've read <a href="https://shkspr.mobi/blog/2020/02/book-review-the-entrepreneurial-state/">The Entrepreneurial State</a>, you'll know that governments are often responsible for subsidising technological initiatives like this. The state, its citizenry, and its businesses all benefit from the increased efficiencies of electronic communications, so it is only right that the state should bootstrap these sorts of projects.</p>
<p>I sent an <a href="https://www.whatdotheyknow.com/request/historical_documents_relating_to">FoI request to find out more</a> but it looks like all the information is now archived.</p>
<p>If you know of any other sources of information about Project Vanguard - please leave a comment.</p>
Completely oblivious people - Cool As Heckhttps://cool-as-heck.blog/completely-oblivious-people2026-01-31T20:34:14.000Z<div>We just went to Wild Hare cider in Berryville. We usually love going there, but today we got there a few minutes before they opened at 2pm. We're sitting in the parking lot, and we see a car rush into the parking lot and a guy jumps out of the car and hurries into the building. Clearly, this guy was late for work.</div>
<div><br></div>
<div>So we give him a few minutes before going inside. He greets us and politely says that he is running a little late and just needs a few minutes to set up. We say "no problem" because we are looking around, as the place has changed a lot since we've been there over a year ago.</div>
<div><br></div>
<div>We finally sit down at the bar, he turns on Spotify on one of the TVs in the corner and starts playing music at a low volume, then turns on THE SHINING on the TV near us at the bar. Like yeah we just came for a drink and a horror movie.</div>
<div><br></div>
<div>It's important to know that this place is just a room in an old warehouse. It's not really heated. They have a couple heaters around the area but only one of them is on. We both still have our coats on as we're sitting at the bar, AND THIS DUDE OPENS THE GARAGE DOOR TO THE OUTSIDE. It's 18°F here today. We look at each other like "we gotta drink this shit and get the hell outta here" because we are going to freeze to death. About that time, another couple comes in and they're like "why is this door open? It's freezing!" The guys says "well I thought it was too dark in here." Both my wife and I and the other couple say "we would rather it be dark and warm." So he closes the door, but by that time we are basically done with our drinks and shivering, so we settled up and left.</div>
<div><br></div>
<div>Now we are home and it is time for a warm nap.</div>
Book Review: With the End in Mind - Dying, Death and Wisdom in an Age of Denial by Kathryn Mannix ★★★⯪☆ - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=665072026-01-31T12:34:55.000Z<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/02/710p3WD9bIL._SL1500_.jpg" alt="Book cover." width="200" class="alignleft size-full wp-image-66509"/>
<p>Is it possible to "die well"? We have midwives for births, should we have "deathwives" for the other end of our lives? I think this book was recommended to me in the depths of the pandemic. I was too much of a chicken to read it while those around me were dying. The book aims to normalise the process of death and mostly succeeds. Unlike a lot of books, it doesn't just identify a problem - it provides pages of solutions. Every chapter ends with a series of questions to ask yourself (or your loved ones) about death.</p>
<p>At times, it is utterly heartbreaking and more than a little gruesome. Death is emotionally <em>and</em> physically distressing. Similarly, there are several stories which deal with the reality of assisted dying. I <em>think</em> the author comes down against euthanasia - but it certainly helps raise questions of whether repeatedly offering the option amounts to pressuring them into an unwanted decision.</p>
<p>It is a <em>bit</em> homespun and cloying. I felt like it painted quite a rosy picture of what death can look like. All the nurses are angels and the doctors have endless patience, there's always time for a cuppa and deathbed revelations are never awkward.</p>
<p>Oh, and there's a lovely aside about <a href="https://openbenches.org/">memorial benches</a> being harbingers of doom, which I found quite amusing!</p>
<p>This will probably sit unread on your ebook for far too long - but it is worth cracking it open and thinking about the questions it raises.</p>
Your Life is the Sum Total of 2,000 Mondays - Westenberg697d47a6141f77000146a14a2026-01-31T00:25:46.000Z<img src="https://images.unsplash.com/photo-1523821741446-edb2b68bb7a0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI3fHxhYnN0cmFjdHxlbnwwfHx8fDE3Njk4MTgyNjR8MA&ixlib=rb-4.1.0&q=80&w=2000" alt="Your Life is the Sum Total of 2,000 Mondays"><p>We plan our lives like we're editing a movie trailer.</p><p>The trip to Portugal, or the product launch, or the transformation photo at the gym. The big moment where everything crystallizes into meaning. We accumulate these peaks in our imagination, and then arrange them into a montage that proves our existence mattered, and that we really <em>lived</em>.</p><p>Then we spend the actual substance of our lives doing laundry and feeling crappy about it...</p><p>A few years ago, I saw Douglas Coupland (author of Microserfs and Generation X, and one of my personal favorite writers) on a panel at the Sydney Writers' Festival. One of the other panelists - an influencer with a recently published quasi-self-help memoir - delivered a long, dreamy anecdote about finding the true meaning of life while watching butterflies drift over a waterfall in some far-flung locale. </p><p>When she finished, the moderator asked Coupland what he thought. </p><p>He said butterflies and waterfalls are all well and good, but they're not real life. They're a flash in the pan - a spike of adrenaline and dopamine. And if you can only find meaning in those brief, luminous moments, you're in for a world of trouble.</p><p>Put it another way:</p><p>If you work a standard career from twenty-five to sixty-five, you'll experience roughly 2,080 Mondays. That's 2,080 alarm clocks set against your biological preferences and 2,080 inbox avalanches, plus 2,080 instances of navigating traffic or public transit while still metabolically processing the weekend. Add in the Tuesdays through Fridays, and you're looking at roughly 10,400 ordinary workdays across a career. Meanwhile, if you're fortunate enough to take two weeks of vacation annually for forty years, you'll accumulate 560 vacation days. The ratio is roughly 19:1 in favor of the mundane.</p><p>So we get to a question worth sitting with: </p><p><em>Do you actually like your average Monday?</em></p><h2 id="the-peak-experience-fallacy">The peak experience fallacy</h2><p>Abraham Maslow spent decades studying what he called "peak experiences," those episodes of ecstasy and transcendence that seemed to characterize the healthiest human specimens. His 1964 work on self-actualization celebrated these episodes as evidence of psychological flourishing, and the positive psychology movement that followed made peak experience cultivation into something approaching a secular religion. </p><p>(And don't we love a good secular religion.) </p><p>But in Maslow's research he deliberately selected subjects he considered "self-actualizing" and then studied what made them tick. The peak experiences he documented were symptoms of people who'd already figured out something more fundamental.</p><p>What Maslow's self-actualizers actually had in common was what he would later come to call "plateau living," a sustained capacity to appreciate ordinary existence, to find the sacred in the quotidian. The peaks were outgrowths of the plateaus, not replacements for them.</p><p>Somehow, this part of the research didn't make it onto the Instagram motivation accounts.</p><p>Romanticism in the nineteenth century made the extraordinary moment into a spiritual imperative. Wordsworth's "spots of time," the vivid memories that restore the imagination, became cultural programming. We inherited the assumption that <em>meaning</em> lives in the exceptional rather than the everyday // that the proof of a life well-lived is a collection of dramatic set pieces.</p><h2 id="the-tolerated-life-problem">The tolerated life problem</h2><p>The psychologist Philip Zimbardo has a framework called "time perspective theory." People differ in how much mental weight they assign to past, present, and future. Future-oriented people tend to achieve more by conventional metrics, but they also exhibit a consistent pattern of sacrificing present satisfaction for hypothetical future rewards. When researchers follow these people over time, they find that the anticipated future keeps receding and the scaffolding remains permanent.</p><p>Seneca diagnosed this exact pathology in first-century Rome. He observed that people guard their property vigilantly but waste their time freely, treating it as an infinite resource. "You act like mortals in all that you fear, and like immortals in all that you desire," he wrote.</p><p>The barely tolerated Monday is a down payment on a life that never arrives, a perpetual advance payment for goods that don't ship.</p><p>Neuroplasticity works both ways. Every Monday you survive without presence, you're training your nervous system that survival is the appropriate response to ordinary life. The brain gets efficient at what it practices, and if it practices endurance, endurance becomes its resting state. You build tolerance in the drug addiction sense: you need more and more peak moments to feel alive because your baseline has been chemically optimized for numbness.</p><h2 id="the-architecture-of-an-ordinary-day">The architecture of an ordinary day</h2><p>If your life is going to be 80% Mondays and their equivalents, the design specifications for Monday matter more than the design specifications for your vacation.</p><p>The three levers that actually move the needle on everyday experience are pretty much consistent: environment, commitments, body, and the way they interact.</p><p>The concrete physical and social circumstances of ordinary days are what matter.</p><p><strong>Environment</strong> shapes behavior more powerfully than willpower. Kurt Lewin, the father of social psychology, called this "field theory" - behavior is a function of the person and their environment simultaneously. The architectural critic Christopher Alexander spent decades documenting how physical spaces create what he called "quality without a name," that feeling of aliveness and coherence that certain places generate. Your Monday morning unfolds in a specific physical context. If that context is cluttered and friction-laden, you're fighting your suroundings before you fight your inbox.</p><p>The writer Annie Dillard, in "The Writing Life:"</p><blockquote>"How we spend our days is, of course, how we spend our lives."</blockquote><p>She was talking specifically of the desk, the chair, the window, and the ritual of beginning. The container shapes the contents.</p><p><strong>Commitments</strong> function as architecture too, but for time rather than space. Every standing meeting and every obligation you've accumulated is making claims on your Mondays whether you consciously choose it or not. The philosopher Harry Frankfurt distinguished between first-order desires (wanting something) and second-order desires (wanting to want something). Most people have a massive gap between what they'd choose if starting fresh and what they've accumulated through drift. Your calendar is probably full of first-order commitments that violate your second-order preferences for how you want to live.</p><p>The economist Albert Hirschman noted that people respond to deterorating situations through exit, through voice, through loyalty, or through some combination of these. Most people default to loyalty with their commitments, enduring obligations that no longer serve them because the activation energy for exit feels too high. But the asymmetry is real: the cost of one difficult conversation is finite, while the cost of tolerating an energy-draining commitment is infinite in the sense that it compounds for as long as you carry it.</p><p><strong>Body</strong> is the substrate everything else runs on, but it's the lever people most consistently ignore when designing their days. You're not a brain piloting a meat vehicle but a single integrated system, and the state of the body on Monday morning is the state of you on Monday morning. The research on sleep and movement is tediously consistent: the basics matter more than the optimizations. No biohacking compensates for six hours of sleep and a pastry for breakfast. The Monday you experience is manufactured in the preceding twenty-four hours.</p><h2 id="the-monday-blueprint">The Monday blueprint</h2><p>Given all this, what would it look like to actually take Monday seriously as a design problem?</p><p>The first hour matters disproportionately. What you do between waking and starting work is the foundation that everything else builds on. If that first hour is wasted in ractive scrolling and rushed caffeine, you've primed your nervous system for a day of low-grade stress. If it's spent in intentional movement and even ten minutes of something that feels like choice rather than obligation, you've shifted the baseline entirely.</p><p>Most people's work blocks are structurally hostile to focus. Cal Newport has beaten the drum on deep work for years now, and the data supports him: the average knowledge worker can't go more than a few minutes without context-switching, and every switch carries cognitive costs. Your Monday needs a protected window, two hours minimum, where the work that actually matters happens without interruption; it needs the satisfaction that comes from making measurable progress on something that matters to you.</p><p>The body work is unglamorous: thirty minutes of movement and food that doesn't spike your blood sugar. Some kind of break from the sedntary. This is maintenance more than optimization, and treating it as optional is how you get to Friday afternoon feeling like you've been through the Somme.</p><p>Lastly: relationships. </p><p>One genuine human connection per Monday and one conversation that goes beyond the transactional changes the texture of the entire day.</p><p>The longitudinal research on wellbeing, from the Harvard Study of Adult Development running since 1938 to more recent epidemiological work, keeps landing on the same finding: the quality of human relationships is the single strongest predictor of flourishing. </p><p>...And that's about it. </p><p>It's not prescriptive. </p><p>There are no lifehacks. </p><p>But the blueprint works. </p><h2 id="building-identity-through-iteration">Building identity through iteration</h2><p>Virtue is a practice, not a possession. You become what you repeatedly do, which means your Mondays are literally building the person you're becoming. Every Monday you survive is training you to be a survivor, and every Monday you engage with is training you to be someone who engages.</p><p>James Clear has popularized the notion of identity-based habits: rather than focusing on outcomes, focus on becoming the type of person who naturally produces those outcomes. Applied to Monday, the question shifts from "How do I get through this day?" to "Who is the person I'm becoming through how I spend this day?" The first question optimizes for survival while the second optimizes for construction.</p><p>Your life is made of ordinary days, and if those ordinary days are spent waiting for something better, you've wished away your existence.</p><p>The goal isn't a life with more peak moments. I think that's a false and ever-elusve pursuit. The goal is a life whose default setting doesn't require escape. Your future is made of boring days done on purpose, and a life you need a vacation from is a design problem rather than a motivation problem.</p><p>The most honest mirror you own is your calendar, and if you looked at your calendar for the last month without knowing whose it was, would you want that person's life?</p><p>In Louis Malle's 1981 film My Dinner with Andre, two old friends sit in a Manhattan restaurant and talk for two hours. And yes, that's the entire movie. And yes, it's one of the best films I've ever seen.</p><p>Andre Gregory, the theater director, has returned from years of seeking transcendence through increasingly elaborate experiences: working with Grotowski in Poland, being buried alive in a forest on Halloween, traveling to the Sahara, and participating in rituals designed to shatter ordinary consciousness. He describes these adventures with genuine wonder, convinced that modern life has anesthetized us and that only extreme experience can wake us up.</p><p>Wallace Shawn listens, fascinated but increasingly skeptical, and then he pushes back. Why, he asks, is it necessary to go to Mount Everest or get buried alive to appreciate existence? Why can't the awareness Andre found in a Polish forest be found right here, having a cup of coffee? "I think if you could become fully aware of what existed in the cigar store next door to this restaurant," Shawn says, "it would blow your head off."</p><p>This is The Work™️: learning to be fully present in a cigar store rather than accumulating butterflies and waterfalls or optimizing for the highlight reel. The transcendence Andre chased across continents was always available in the texture of an ordinary afternoon, an ordinary Monday. He couldn't access it because he believed that meaning lives in the hard-to-pin-down "elsewhere."</p><p>Your Mondays are not obstacles between you and your real life. </p><p>They are your real life, and all that remains is whether you're awake for them.</p>Note published on January 30, 2026 at 3:16 PM UTC - Molly White's activity feed697ccb3e498c9cae1763ab3c2026-01-30T15:16:14.000Z<article><div class="entry h-entry hentry"><header></header><div class="content e-content"><p>Binance bitcoin bailout<br></p><p>It does not seem to me to bode well that they’re getting this nervous when the bitcoin price hasn’t even dropped below $80,000</p><div class="media-wrapper invert-on-dark"><a href="https://storage.mollywhite.net/micro/7da820cd465281e0bbf6_Screenshot-2026-01-30-at-10.15.07---AM.png" data-fslightbox=7555559050cec7053f5e><img src="https://storage.mollywhite.net/micro/7da820cd465281e0bbf6_Screenshot-2026-01-30-at-10.15.07---AM.png" alt="Headline: Binance to shift $1 billion user protection fund into bitcoin amid market rout Binance will convert the stablecoin holdings in its $1 billion Secure Asset Fund for Users to bitcoin over the next 30 days, with plans for regular audits" /></a></div></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp-block"><div class="timestamp">Posted: <a href="https://www.mollywhite.net/micro/entry/202601301015"><time class="dt-published" datetime="2026-01-30T15:16:14+00:00" title="January 30, 2026 at 3:16 PM UTC">January 30, 2026 at 3:16 PM UTC</time>. </a></div><div class="timestamp">Updated <time class="dt-updated" datetime="2026-01-30T15:21:46+00:00" title="January 30, 2026 at 3:21 PM UTC">January 30, 2026 at 3:21 PM UTC</time>.</div></div><div class="social-links"> <span> Also posted to: </span><a class="social-link u-syndication mastodon" href="https://hachyderm.io/@molly0xfff/115984706901526780" title="Mastodon" rel="syndication">Mastodon, </a><a class="social-link u-syndication bluesky" href="https://bsky.app/profile/molly.wiki/post/3mdnlunb4ov2a" 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/binance" title="See all micro posts tagged "Binance"" rel="category tag">Binance</a>, <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/bitcoin" title="See all micro posts tagged "bitcoin"" rel="category tag">bitcoin</a>, <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/crypto" title="See all micro posts tagged "crypto"" rel="category tag">crypto</a>. </div></div></footer></div></article>Theatre Review: The Hitchhiker’s Guide to The Galaxy - Immersive Experience ★★★⯪☆ - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=673842026-01-30T12:34:41.000Z<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/01/zp1ca_69419b672e32c.jpg" alt="Promo image. People standing on a planet with a depressed robot." width="250" class="alignleft size-full wp-image-67386"/>
<p>You've read the books, listened to the original radio performances, re-read the books, worn the t-shirt - and now it is time to be <em>part</em> of The Hitchhiker’s Guide to The Galaxy.</p>
<p>*<em>Cue the music from Flight of the Sorcerer</em>*</p>
<p>This is a 90-ish minute immersive experience. As well as a full cast of actors and a puppet android, there are ✨celebrity✨ voice cameos.</p>
<p>And songs! So many songs!</p>
<h2 id="pre-show"><a href="https://shkspr.mobi/blog/2026/01/theatre-review-the-hitchhikers-guide-to-the-galaxy-immersive-experience/#pre-show">Pre Show</a></h2>
<p>I'm always interested in how <a href="https://shkspr.mobi/blog/2024/12/the-art-of-the-pre-show-and-post-show/">shows build excitement before a performance</a>. We were encouraged to arrive early to stash our coats (a very reasonable £1 each) and soak up the atmosphere.</p>
<p>It mostly works! We're deposited into the pub with <em>lots</em> of texture. As well as multiple screens displaying a variety on in-jokes, the actors hobnob with the guests. Nifty!</p>
<h2 id="show"><a href="https://shkspr.mobi/blog/2026/01/theatre-review-the-hitchhikers-guide-to-the-galaxy-immersive-experience/#show">Show</a></h2>
<p>From a technology perspective, the show is astonishingly good. Laser display boards mixed with puppets, dry ice, surround sound, and a hundred little decorations to notice. The actors are witty and talented improvisers. They did well with the matinée audience who needed a little warming up. There's a bar halfway through the experience where you can buy a (typically overpriced) branded beer - but I'd recommend having a warm up Pan Galactic Gargle Blaster in the bar before the show.</p>
<p>Wandering around the Vogon ship is a sonic and visual delight. The chaos of running between the sets feels utterly on-brand for H2G2. The sets are lush and, as mentioned, the technology integrates well with the story.</p>
<p>So, about the story.</p>
<p>There is no continuity in this franchise. Canon is noticeable by its absence and you should throw most of your preconceptions of plot out of the window. This isn't a cosy retread of the books you loved, nor is it a something entirely new. Essentially it is a series of sketches ripped and remixed from various versions. It kind of felt like there was a missing segment in the show - characters disappeared (to go perform for the next set of participants) and then reappeared.</p>
<p>If you have even a passing familiarity with H2G2 (in any of its forms) then I think you'll enjoy it. If not, I think it is a little scattershot. 90 minutes isn't enough to build up much of the complexity or tension in the drama. That said, it is rather jolly fun and surprisingly tender.</p>
<h2 id="post-show"><a href="https://shkspr.mobi/blog/2026/01/theatre-review-the-hitchhikers-guide-to-the-galaxy-immersive-experience/#post-show">Post Show</a></h2>
<p>It isn't quite "exit through the gift shop" but not far off. I remember how the end of the Alien experience in the Trocadero had audience members running out into a public area - here it's a gentle stroll into the bar.</p>
<p>This is a worthy addition to the many different adaptations of Douglas Adams' opus.</p>
<p>The experience runs until the 15th of February at the Riverside Studios. Tickets start at, of course, £42.</p>
Celebrating our 2025 open-source contributions - Trail of Bits Bloghttps://blog.trailofbits.com/2026/01/30/celebrating-our-2025-open-source-contributions/2026-01-30T12:00:00.000Z<p>Last year, our engineers submitted over <strong>375 pull requests</strong> that were merged into non–Trail of Bits repositories, touching more than <strong>90 projects</strong> from cryptography libraries to the Rust compiler.</p>
<p>This work reflects one of our driving values: “share what others can use.” The measure isn’t whether you share something, but whether it’s actually useful to someone else. This principle is why we publish <a href="https://github.com/trailofbits/publications?tab=readme-ov-file#guides-and-handbooks">handbooks</a>, write blog posts, and release tools like <a href="https://github.com/trailofbits/skills">Claude skills</a>, <a href="https://github.com/crytic/slither">Slither</a>, <a href="https://github.com/trailofbits/buttercup">Buttercup</a>, and <a href="https://github.com/trailofbits/anamorpher">Anamorpher</a>.</p>
<p>But this value isn’t limited to our own projects; we also share our efforts with the wider open-source community. When we hit limitations in tools we depend on, we fix them upstream. When we find ways to make the software ecosystem more secure, we contribute those improvements.</p>
<p>Most of these contributions came out of client work—we hit a bug we were able to fix or wanted a feature that didn’t exist. The lazy option would have been forking these projects for our needs or patching them locally. Contributing upstream instead takes longer, but it means the next person doesn’t have to solve the same problem. Some of our work is also funded directly by organizations like the OpenSSF and Alpha-Omega, who we collaborate with to make things better for everyone.</p>
<h2 id="key-contributions">Key contributions</h2>
<ul>
<li><a href="https://github.com/sigstore/rekor-monitor"><strong>Sigstore rekor-monitor</strong></a>: rekor-monitor verifies and monitors the Rekor transparency log, which records signing events for software artifacts. With funding from OpenSSF, we’ve been <a href="https://blog.trailofbits.com/2025/12/12/catching-malicious-package-releases-using-a-transparency-log/">getting rekor-monitor ready for production use</a>. We contributed over 40 pull requests to the Rekor project this year, including <a href="https://github.com/sigstore/rekor-monitor/pull/764">support for custom certificate authorities</a> and <a href="https://github.com/sigstore/rekor-monitor/pull/705">support for the new Rekor v2</a>. We also <a href="https://github.com/sigstore/rekor-monitor/pull/751">added identity monitoring</a> for <a href="https://github.com/sigstore/rekor-tiles">Rekor v2</a>, which lets package maintainers configure monitored certificate subjects and issuers and then receive alerts whenever matching entries appear in the log. If someone compromises your release process and signs a malicious package with your identity, you’ll know.</li>
<li><a href="https://github.com/rust-lang/rust"><strong>Rust compiler</strong></a> <strong>and <a href="https://github.com/rust-lang/rust-clippy">rust-clippy</a></strong>: Clippy is Rust’s official linting tool, offering over 750 lints to catch common mistakes. We contributed over 20 merged pull requests this year. For example, we <a href="https://github.com/rust-lang/rust-clippy/pull/14177">extended the <code>implicit_clone</code> lint to handle <code>to_string()</code> calls</a>, which let us deprecate the redundant <code>string_to_string</code> lint. We <a href="https://github.com/rust-lang/rust-clippy/pull/13669">added replacement suggestions to <code>disallowed_methods</code></a> so that teams can suggest alternatives when flagging forbidden API usage, and we <a href="https://github.com/rust-lang/rust-clippy/pull/14397">added path validation for <code>disallowed_*</code> configurations</a> so that typos don’t silently disable lint rules. We also <a href="https://github.com/rust-lang/rust/pull/139345">extended the <code>QueryStability</code> lint to handle <code>IntoIterator</code> implementations</a> in rustc, which catches nondeterminism bugs in the compiler. The motivation came from a real issue we spotted: iteration order over hash maps was leaking into rustdoc’s JSON output.</li>
<li><a href="https://github.com/pyca/cryptography"><strong>pyca/cryptography</strong></a>: pyca/cryptography is Python’s most widely used cryptography library, providing both high-level recipes and low-level interfaces to common algorithms. With funding from Alpha-Omega, we landed 28 pull requests this year. Our work was aimed at adding <a href="https://github.com/pyca/cryptography/pull/13325">a new ASN.1 API</a>, which lets developers define ASN.1 structures using Python decorators and type annotations instead of wrestling with raw bytes or external schema files. Read more in our blog post “<a href="https://blog.trailofbits.com/2025/04/18/sneak-peek-a-new-asn.1-api-for-python/">Sneak peek: A new ASN.1 API for Python</a>.”</li>
<li><a href="https://github.com/ethereum/hevm"><strong>hevm</strong></a>: hevm is a Haskell implementation of the Ethereum Virtual Machine. It powers both the symbolic and concrete execution in Echidna, our smart contract fuzzer. We contributed 14 pull requests this year, mostly focused on performance: we <a href="https://github.com/ethereum/hevm/pull/803">added cost centers to individual opcodes to ease profiling, optimized memory operations, and made stack and program counter operations strict</a>, which got us double-digit percentage improvements on concrete execution benchmarks. We also implemented cheatcodes like <a href="https://github.com/ethereum/hevm/pull/838"><code>toString</code></a> to improve hevm’s compatibility with Foundry.</li>
<li><a href="https://github.com/pypi/warehouse"><strong>PyPI Warehouse</strong></a>: Warehouse powers the Python Package Index (PyPI), which serves over a billion package downloads per day. We continued our long-running collaboration with PyPI and Alpha-Omega, shipping <a href="https://blog.trailofbits.com/2025/01/30/pypi-now-supports-archiving-projects/">project archival support</a> so that maintainers can signal when packages are no longer actively maintained. We also <a href="https://blog.trailofbits.com/2025/05/01/making-pypis-test-suite-81-faster/">cut the test suite runtime by 81%</a>, from 163 to 30 seconds, even as test coverage grew to over 4,700 tests.</li>
<li><a href="https://github.com/pwndbg/pwndbg"><strong>pwndbg</strong></a>: pwndbg is a GDB and LLDB plugin that makes debugging and exploit development less painful. Last year, we <a href="https://github.com/pwndbg/pwndbg/pull/3195">packaged LLDB support for distributions</a> and <a href="https://github.com/pwndbg/pwndbg/pull/3548">improved decompiler integration</a>. We also contributed pull requests to other tools in the space, including pwntools, angr, and Binary Ninja’s API.</li>
</ul>
<p>A merged pull request is the easy part. The hard part is everything maintainers do before and after: writing extensive documentation, keeping CI green, fielding bug reports, explaining the same thing to the fifth person who asks. We get to submit a fix and move on. They’re still there a year later, making sure it all holds together.</p>
<p>Thanks to everyone who shaped these contributions with us, from first draft to merge. See you next year.</p>
<h2 id="trail-of-bits-2025-open-source-contributions">Trail of Bits’ 2025 open-source contributions</h2>
<h3 id="aiml">AI/ML</h3>
<ul>
<li>Repo: majiayu000/litellm-rs
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/majiayu000/litellm-rs/pull/3">#3: Specify Anthropic key with <code>x-api-key</code> header</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: mlflow/mlflow
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/mlflow/mlflow/pull/18274">#18274: Fix type checking in truncation message extraction (#18249)</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: simonw/llm
<ul>
<li>By <a href="https://github.com/dguido">dguido</a>
<ul>
<li><a href="https://github.com/simonw/llm/pull/950">#950: Add model_name parameter to OpenAI extra models documentation</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sst/opencode
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/sst/opencode/pull/4549">#4549: tweak: Prefer VISUAL environment variable over EDITOR per Unix convention</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="cryptography">Cryptography</h3>
<ul>
<li>Repo: C2SP/x509-limbo
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/C2SP/x509-limbo/pull/381">#381: deps: pin oscrypto to a git ref</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/382">#382: dependabot: use groups</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/385">#385: add webpki::nc::nc-permits-dns-san-pattern</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/386">#386: chore: switch to uv</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/387">#387: chore: clean up the site a bit</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/414">#414: chore: fixup rustls-webpki API usage</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/418">#418: add openssl-3.5 harness</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/419">#419: perf: remove PEM bundles from site render</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/420">#420: pyca: harness: fix max_chain_depth condition</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/434">#434: chore(ci): arm64 runners, pinact</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/435">#435: mkdocs: disable search</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/437">#437: chore: bump limbo</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/445">#445: feat: add CRL builder API</a></li>
<li><a href="https://github.com/C2SP/x509-limbo/pull/446">#446: fix: avoid a redundant condition + bogus type ignore</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: certbot/josepy
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/certbot/josepy/pull/193">#193: ci: don’t persist creds in check.yaml</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pyca/cryptography
<ul>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/pyca/cryptography/pull/12807">#12807: Update license metadata in <code>pyproject.toml</code> according to PEP 639</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13325">#13325: Initial implementation of ASN.1 API</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13449">#13449: Add decoding support to ASN.1 API</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13476">#13476: Unify ASN.1 encoding and decoding tests</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13482">#13482: asn1: Add support for bytes, str and bool</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13496">#13496: asn1: Add support for <code>PrintableString</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13514">#13514: x509: rewrite datetime conversion functions</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13513">#13513: asn1: Add support for <code>UtcTime</code> and <code>GeneralizedTime</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13542">#13542: asn1: Add support for <code>OPTIONAL</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13570">#13570: Fix coverage for declarative_asn1/decode.rs</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13571">#13571: Fix some coverage for declarative_asn1/types.rs</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13573">#13573: Fix coverage for <code>type_to_tag</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13576">#13576: Fix more coverage for declarative_asn1/types.rs</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13580">#13580: Fix coverage for pyo3::DowncastIntoError conversion</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13579">#13579: Fix coverage for declarative_asn1::Type variants</a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13562">#13562: asn1: Add support for <code>DEFAULT</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13735">#13735: asn1: Add support for <code>IMPLICIT</code> and <code>EXPLICIT</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13894">#13894: asn1: Add support for <code>SEQUENCE OF</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13899">#13899: asn1: Add support for <code>SIZE</code> to <code>SEQUENCE OF</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13908">#13908: asn1: Add support for <code>BIT STRING</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13985">#13985: asn1: Add support for <code>IA5String</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13986">#13986: asn1: Add TODO comment for uses of <code>PyStringMethods::to_cow</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/13999">#13999: asn1: Add <code>SIZE</code> support to <code>BIT STRING</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/14032">#14032: asn1: Add <code>SIZE</code> support to <code>OCTET STRING</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/14036">#14036: asn1: Add <code>SIZE</code> support to <code>UTF8String</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/14037">#14037: asn1: Add <code>SIZE</code> support to <code>PrintableString</code></a></li>
<li><a href="https://github.com/pyca/cryptography/pull/14038">#14038: asn1: Add <code>SIZE</code> support to <code>IA5String</code></a></li>
</ul>
</li>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pyca/cryptography/pull/12253">#12253: x509/verification: allow DNS wildcard patterns to match NCs</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: tamarin-prover/tamarin-prover
<ul>
<li>By <a href="https://github.com/arcz">arcz</a>
<ul>
<li><a href="https://github.com/tamarin-prover/tamarin-prover/pull/687">#687: Refactor tamaring-prover-sapic</a></li>
<li><a href="https://github.com/tamarin-prover/tamarin-prover/pull/686">#686: Refactor tamarin-prover-accountability</a></li>
<li><a href="https://github.com/tamarin-prover/tamarin-prover/pull/621">#621: Refactor tamarin-prover package</a></li>
<li><a href="https://github.com/tamarin-prover/tamarin-prover/pull/755">#755: Refactor tamarin-prover-sapic records</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="languages-and-compilers">Languages and compilers</h3>
<ul>
<li>Repo: airbus-cert/tree-sitter-powershell
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/airbus-cert/tree-sitter-powershell/pull/17">#17: deps: bump tree-sitter to 0.25.2</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: cdisselkoen/llvm-ir
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/cdisselkoen/llvm-ir/pull/69">#69: lib: add missing llvm-19 case</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: hyperledger-solang/solang
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1680">#1680: Fixes two <code>elided_named_lifetimes</code> warnings</a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1788">#1788: Fix typo in codegen/dispatch/polkadot.rs</a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1778">#1778: Check command statuses in build.rs</a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1779">#1779: Fix two infinite loops in codegen</a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1791">#1791: Fix typos in tests/polkadot.rs</a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1793">#1793: Fix a small typo affecting <code>Expression::GetRef</code></a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1802">#1802: Rename <code>binary</code> to <code>bin</code></a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1801">#1801: Handle <code>abi.encode()</code> with empty args</a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1800">#1800: Store <code>Namespace</code> reference in <code>Binary</code></a></li>
<li><a href="https://github.com/hyperledger-solang/solang/pull/1837">#1837: Silence <code>mismatched_lifetime_syntaxes</code> lint</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: llvm/clangir
<ul>
<li>By <a href="https://github.com/wizardengineer">wizardengineer</a>
<ul>
<li><a href="https://github.com/llvm/clangir/pull/1859">#1859: \[CIR\] Fix parsing of #cir.unwind and cir.resume for catch regions</a></li>
<li><a href="https://github.com/llvm/clangir/pull/1861">#1861: \[CIR\] Added support for <code>__builtin_ia32_pshufd</code></a></li>
<li><a href="https://github.com/llvm/clangir/pull/1874">#1874: \[CIR\] Add CIRGenFunction::getTypeSizeInBits and use it for size computation</a></li>
<li><a href="https://github.com/llvm/clangir/pull/1883">#1883: \[CIR\] Added support for <code>__builtin_ia32_pslldqi_byteshift</code></a></li>
<li><a href="https://github.com/llvm/clangir/pull/1964">#1964: \[CIR\]\[NFC\] Using types explicitly for <code>pslldqi</code> construct</a></li>
<li><a href="https://github.com/llvm/clangir/pull/1886">#1886: \[CIR\] Add support for <code>__builtin_ia32_psrldqi_byteshift</code></a></li>
<li><a href="https://github.com/llvm/clangir/pull/2055">#2055: \[CIR\] Backport FileScopeAsm support from upstream</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: rust-lang/rust
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/rust-lang/rust/pull/139345">#139345: Extend <code>QueryStability</code> to handle <code>IntoIterator</code> implementations</a></li>
<li><a href="https://github.com/rust-lang/rust/pull/145533">#145533: Reorder <code>lto</code> options from most to least optimizing</a></li>
<li><a href="https://github.com/rust-lang/rust/pull/146120">#146120: Correct typo in <code>rustc_errors</code> comment</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="libraries">Libraries</h3>
<ul>
<li>Repo: alex/rust-asn1
<ul>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/alex/rust-asn1/pull/532">#532: Make <code>Parser::peek_tag</code> public</a></li>
<li><a href="https://github.com/alex/rust-asn1/pull/533">#533: Re-add <code>Parser::read_{explicit,implicit}_element</code> methods</a></li>
<li><a href="https://github.com/alex/rust-asn1/pull/535">#535: Fix CHOICE docs to match current API</a></li>
<li><a href="https://github.com/alex/rust-asn1/pull/563">#563: Re-add <code>Writer::write_{explicit,implicit}_element</code> methods</a></li>
<li><a href="https://github.com/alex/rust-asn1/pull/581">#581: Release version 0.23.0</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: bytecodealliance/wasi-rs
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/bytecodealliance/wasi-rs/pull/103">#103: Upgrade <code>wit-bindgen-rt</code> to version 0.39.0</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: cargo-public-api/cargo-public-api
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/cargo-public-api/cargo-public-api/pull/831">#831: <code>Box<dyn ...></code> with two or more traits</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: di/id
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/di/id/pull/333">#333: refactor: replace requests with urllib3</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: di/pip-api
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/di/pip-api/pull/237">#237: tox: add pip 25.0 to the test matrix</a></li>
<li><a href="https://github.com/di/pip-api/pull/240">#240: _call: invoke pip with PYTHONIOENCODING=utf8</a></li>
<li><a href="https://github.com/di/pip-api/pull/242">#242: tox: add pip 25.0.1 to the envlist</a></li>
<li><a href="https://github.com/di/pip-api/pull/247">#247: tox: add pip 25.1.1 to test matrix</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: fardream/go-bcs
<ul>
<li>By <a href="https://github.com/tjade273">tjade273</a>
<ul>
<li><a href="https://github.com/fardream/go-bcs/pull/19">#19: Fix unbounded upfront allocations</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: frewsxcv/rust-crates-index
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/frewsxcv/rust-crates-index/pull/189">#189: Add <code>git-https-reqwest</code> feature</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: luser/strip-ansi-escapes
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/luser/strip-ansi-escapes/pull/21">#21: Upgrade <code>vte</code> to version 0.14</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: psf/cachecontrol
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/psf/cachecontrol/pull/350">#350: chore: prep 0.14.2</a></li>
<li><a href="https://github.com/psf/cachecontrol/pull/352">#352: tests: explicitly GC for PyPy in test_do_not_leak_response</a></li>
<li><a href="https://github.com/psf/cachecontrol/pull/379">#379: chore(ci): fix pins with <code>gha-update</code></a></li>
<li><a href="https://github.com/psf/cachecontrol/pull/381">#381: chore: drop python 3.8 support, prep for release</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: tafia/quick-xml
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/tafia/quick-xml/pull/904">#904: Implement serializing CDATA</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="tech-infrastructure">Tech infrastructure</h3>
<ul>
<li>Repo: Homebrew/homebrew-core
<ul>
<li>By <a href="https://github.com/elopez">elopez</a>
<ul>
<li><a href="https://github.com/Homebrew/homebrew-core/pull/206517">#206517: slither-analyzer 0.11.0</a></li>
<li><a href="https://github.com/Homebrew/homebrew-core/pull/254439">#254439: slither-analyzer: bump python resources</a></li>
</ul>
</li>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/homebrew-core/pull/206391">#206391: sickchill: bump Python resources</a></li>
<li><a href="https://github.com/Homebrew/homebrew-core/pull/206675">#206675: ci: switch to SSH signing everywhere</a></li>
<li><a href="https://github.com/Homebrew/homebrew-core/pull/222973">#222973: zizmor: add tab completion</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: NixOS/nixpkgs
<ul>
<li>By <a href="https://github.com/elopez">elopez</a>
<ul>
<li><a href="https://github.com/NixOS/nixpkgs/pull/421573">#421573: libff: remove boost dependency</a></li>
<li><a href="https://github.com/NixOS/nixpkgs/pull/442246">#442246: echidna: 2.2.6 -> 2.2.7</a></li>
<li><a href="https://github.com/NixOS/nixpkgs/pull/445662">#445662: libff: update cmake version</a></li>
<li><a href="https://github.com/NixOS/nixpkgs/pull/445678">#445678: btor2tools: 0-unstable-2024-08-07 -> 0-unstable-2025-09-18</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: google/oss-fuzz
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/google/oss-fuzz/pull/14080">#14080: projects/libpng: make sure master branch is used</a></li>
<li><a href="https://github.com/google/oss-fuzz/pull/14178">#14178: infra/helper: pass the right arguments to docker_run in reproduce_impl</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: microsoft/vcpkg
<ul>
<li>By <a href="https://github.com/ekilmer">ekilmer</a>
<ul>
<li><a href="https://github.com/microsoft/vcpkg/pull/45458">#45458: \[abseil\] Add feature “test-helpers”</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: microsoft/vcpkg-tool
<ul>
<li>By <a href="https://github.com/ekilmer">ekilmer</a>
<ul>
<li><a href="https://github.com/microsoft/vcpkg-tool/pull/1602">#1602: Check errno after waitpid for EINTR</a></li>
<li><a href="https://github.com/microsoft/vcpkg-tool/pull/1744">#1744: \[spdx\] Add installed package files to SPDX SBOM file</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="software-testing-tools">Software testing tools</h3>
<ul>
<li>Repo: AFLplusplus/AFLplusplus
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/AFLplusplus/AFLplusplus/pull/2319">#2319: Add <code>fflush(stdout);</code> before <code>abort</code> call</a></li>
<li><a href="https://github.com/AFLplusplus/AFLplusplus/pull/2408">#2408: Color <code>AFL_NO_UI</code> output</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: advanced-security/monorepo-code-scanning-action
<ul>
<li>By <a href="https://github.com/Vasco-jofra">Vasco-jofra</a>
<ul>
<li><a href="https://github.com/advanced-security/monorepo-code-scanning-action/pull/61">#61: Only republish SARIFs from valid projects</a></li>
<li><a href="https://github.com/advanced-security/monorepo-code-scanning-action/pull/58">#58: Add support for passing tools to codeql-action/init</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: github/codeql
<ul>
<li>By <a href="https://github.com/Vasco-jofra">Vasco-jofra</a>
<ul>
<li><a href="https://github.com/github/codeql/pull/19762">#19762: Improve TypeORM model</a></li>
<li><a href="https://github.com/github/codeql/pull/19769">#19769: Improve NestJS sources and dependency injection</a></li>
<li><a href="https://github.com/github/codeql/pull/19768">#19768: Add lodash GroupBy as taint step</a></li>
<li><a href="https://github.com/github/codeql/pull/19770">#19770: Improve data flow in the <code>async</code> package</a></li>
</ul>
</li>
<li>By <a href="https://github.com/mschwager">mschwager</a>
<ul>
<li><a href="https://github.com/github/codeql/pull/20101">#20101: Fix #19294, Ruby NetHttpRequest improvements</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: oli-obk/ui_test
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/oli-obk/ui_test/pull/352">#352: Fix typo in parser.rs</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypa/abi3audit
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypa/abi3audit/pull/134">#134: ci: set some default empty permissions</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: rust-fuzz/cargo-fuzz
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/rust-fuzz/cargo-fuzz/pull/423">#423: Update <code>tempfile</code> to version 3.10.1</a></li>
<li><a href="https://github.com/rust-fuzz/cargo-fuzz/pull/424">#424: Update <code>is-terminal</code> to version 0.4.16</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: rust-lang/cargo
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/rust-lang/cargo/pull/15201">#15201: Typo: “explicitally” -> “explicitly”</a></li>
<li><a href="https://github.com/rust-lang/cargo/pull/15204">#15204: Typo: “togother” -> “together”</a></li>
<li><a href="https://github.com/rust-lang/cargo/pull/15208">#15208: fix: reset $CARGO if the running program is real <code>cargo[.exe]</code></a></li>
<li><a href="https://github.com/rust-lang/cargo/pull/15698">#15698: Fix potential deadlock in <code>CacheState::lock</code></a></li>
<li><a href="https://github.com/rust-lang/cargo/pull/15841">#15841: Reorder <code>lto</code> options in profiles.md</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: rust-lang/rust-clippy
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/13894">#13894: Move <code>format_push_string</code> and <code>format_collect</code> to pedantic</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/13669">#13669: Two improvements to <code>disallowed_*</code></a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/13893">#13893: Add <code>unnecessary_debug_formatting</code> lint</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/13931">#13931: Add <code>ignore_without_reason</code> lint</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/14280">#14280: Rename <code>inconsistent_struct_constructor</code> configuration; don’t suggest deprecated configurations</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/14376">#14376: Make <code>visit_map</code> happy path more evident</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/14397">#14397: Validate paths in <code>disallowed_*</code> configurations</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/14529">#14529: Fix a typo in derive.rs comment</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/14733">#14733: Don’t warn about unloaded crates</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/14360">#14360: Add internal lint <code>derive_deserialize_allowing_unknown</code></a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/15090">#15090: Fix typo in tests/ui/missing_const_for_fn/const_trait.rs</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/15357">#15357: Fix typo non_std_lazy_statics.rs</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/14177">#14177: Extend <code>implicit_clone</code> to handle <code>to_string</code> calls</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/15440">#15440: Correct <code>needless_borrow_for_generic_args</code> doc comment</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/15592">#15592: Commas to semicolons in clippy.toml reasons</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/15862">#15862: Allow <code>explicit_write</code> in tests</a></li>
<li><a href="https://github.com/rust-lang/rust-clippy/pull/16114">#16114: Allow multiline suggestions in <code>map-unwrap-or</code></a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: rust-lang/rustup
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/rust-lang/rustup/pull/4201">#4201: Add <code>TryFrom<Output></code> for <code>SanitizedOutput</code></a></li>
<li><a href="https://github.com/rust-lang/rustup/pull/4200">#4200: Do not append <code>EXE_SUFFIX</code> in <code>Config::cmd</code></a></li>
<li><a href="https://github.com/rust-lang/rustup/pull/4203">#4203: Have mocked cargo better adhere to cargo conventions</a></li>
<li><a href="https://github.com/rust-lang/rustup/pull/4516">#4516: Fix typo in clitools.rs comment</a></li>
<li><a href="https://github.com/rust-lang/rustup/pull/4518">#4518: Set <code>RUSTUP_TOOLCHAIN_SOURCE</code></a></li>
<li><a href="https://github.com/rust-lang/rustup/pull/4549">#4549: Expand <code>RUSTUP_TOOLCHAIN_SOURCE</code>’s documentation</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: zizmorcore/zizmor
<ul>
<li>By <a href="https://github.com/DarkaMaul">DarkaMaul</a>
<ul>
<li><a href="https://github.com/zizmorcore/zizmor/pull/496">#496: Downgrade tracing-indicatif</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="blockchain-software">Blockchain software</h3>
<ul>
<li>Repo: anza-xyz/agave
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/anza-xyz/agave/pull/6283">#6283: Fix typo in cargo-install-all.sh</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: argotorg/hevm
<ul>
<li>By <a href="https://github.com/elopez">elopez</a>
<ul>
<li><a href="https://github.com/argotorg/hevm/pull/612">#612: Cleanups in preparation of GHC 9.8</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/663">#663: tests: run <code>evm</code> on its own directory</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/707">#707: Optimize memory representation and operations</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/729">#729: Optimize <code>maybeLit{Byte,Word,Addr}Simp</code> and <code>maybeConcStoreSimp</code></a></li>
<li><a href="https://github.com/argotorg/hevm/pull/738">#738: Fix Windows CI build</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/744">#744: Add benchmarking with Solidity examples</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/737">#737: Use <code>Storable</code> vectors for memory</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/760">#760: Avoid fixpoint for literals and concrete storage</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/789">#789: Optimized OpSwap</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/803">#803: Add cost centers to opcodes, optimize</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/808">#808: Optimize <code>word256Bytes</code>, <code>word160Bytes</code></a></li>
<li><a href="https://github.com/argotorg/hevm/pull/838">#838: Implement <code>toString</code> cheatcode</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/846">#846: Bump dependency upper bounds</a></li>
<li><a href="https://github.com/argotorg/hevm/pull/883">#883: Fix GHC 9.10 warnings</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: hellwolf/solc.nix
<ul>
<li>By <a href="https://github.com/elopez">elopez</a>
<ul>
<li><a href="https://github.com/hellwolf/solc.nix/pull/21">#21: Update references to solc-bin and solidity repositories</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: rappie/fuzzer-gas-metric-benchmark
<ul>
<li>By <a href="https://github.com/elopez">elopez</a>
<ul>
<li><a href="https://github.com/rappie/fuzzer-gas-metric-benchmark/pull/1">#1: Unify benchmarking code to avoid differences between tools</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="reverse-engineering-tools">Reverse engineering tools</h3>
<ul>
<li>Repo: Gallopsled/pwntools
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/Gallopsled/pwntools/pull/2527">#2527: Allow setting debugger path via <code>context.gdb_binary</code></a></li>
<li><a href="https://github.com/Gallopsled/pwntools/pull/2546">#2546: ssh: Allow passing <code>disabled_algorithms</code> keyword argument from <code>ssh</code> to paramiko</a></li>
<li><a href="https://github.com/Gallopsled/pwntools/pull/2602">#2602: Allow setting debugger path via context.gdb_binary</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: Vector35/binaryninja-api
<ul>
<li>By <a href="https://github.com/ekilmer">ekilmer</a>
<ul>
<li><a href="https://github.com/Vector35/binaryninja-api/pull/6822">#6822: cmake: binaryninjaui depends on binaryninjaapi</a></li>
</ul>
</li>
<li>By <a href="https://github.com/ex0dus-0x">ex0dus-0x</a>
<ul>
<li><a href="https://github.com/Vector35/binaryninja-api/pull/7123">#7123: \[Rust\] Make fields of LookupTableEntry public</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: angr/angr
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/angr/angr/pull/5665">#5665: Check that jump_source is not None</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: angr/angrop
<ul>
<li>By <a href="https://github.com/bkrl">bkrl</a>
<ul>
<li><a href="https://github.com/angr/angrop/pull/124">#124: Implement ARM64 support and RiscyROP chaining algorithm</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: frida/frida-gum
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/frida/frida-gum/pull/1075">#1075: Support data exports on Windows</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: jonpalmisc/screenshot_ninja
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/jonpalmisc/screenshot_ninja/pull/4">#4: Fix api deprecation</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pwndbg/pwndbg
<ul>
<li>By <a href="https://github.com/Ninja3047">Ninja3047</a>
<ul>
<li><a href="https://github.com/pwndbg/pwndbg/pull/2916">#2916: Fix parsing gaps in command line history</a></li>
<li><a href="https://github.com/pwndbg/pwndbg/pull/2920">#2920: Bump zig in nix devshell to 0.13.1</a></li>
<li><a href="https://github.com/pwndbg/pwndbg/pull/2925">#2925: Add editable pwndbg into the nix devshell</a></li>
<li><a href="https://github.com/pwndbg/pwndbg/pull/2928">#2928: Use nixfmt-tree instead of calling the nixfmt-rfc-style directly</a></li>
<li><a href="https://github.com/pwndbg/pwndbg/pull/3194">#3194: fix: exec -a is not posix compliant</a></li>
<li><a href="https://github.com/pwndbg/pwndbg/pull/3195">#3195: Package lldb for distros</a></li>
</ul>
</li>
<li>By <a href="https://github.com/arcz">arcz</a>
<ul>
<li><a href="https://github.com/pwndbg/pwndbg/pull/2942">#2942: Update development with Nix docs</a></li>
<li><a href="https://github.com/pwndbg/pwndbg/pull/3314">#3314: Fix lldb fzf startup prompt</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: quarkslab/quokka
<ul>
<li>By <a href="https://github.com/DarkaMaul">DarkaMaul</a>
<ul>
<li><a href="https://github.com/quarkslab/quokka/pull/42">#42: Update release.yml to use TP and more modern packaging solutions</a></li>
<li><a href="https://github.com/quarkslab/quokka/pull/43">#43: Add dependabot</a></li>
<li><a href="https://github.com/quarkslab/quokka/pull/46">#46: Add zizmor action</a></li>
<li><a href="https://github.com/quarkslab/quokka/pull/30">#30: Allow build on MacOS (MX)</a></li>
<li><a href="https://github.com/quarkslab/quokka/pull/48">#48: Fix zizmor alerts</a></li>
<li><a href="https://github.com/quarkslab/quokka/pull/63">#63: Update LLVM ref to LLVM@18</a></li>
<li><a href="https://github.com/quarkslab/quokka/pull/66">#66: chore: pin GitHub Actions to SHA hashes for security</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="software-analysistransformation-tools">Software analysis/transformation tools</h3>
<ul>
<li>Repo: pygments/pygments
<ul>
<li>By <a href="https://github.com/DarkaMaul">DarkaMaul</a>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/2819">#2819: Add CodeQL lexer</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: quarkslab/bgraph
<ul>
<li>By <a href="https://github.com/DarkaMaul">DarkaMaul</a>
<ul>
<li><a href="https://github.com/quarkslab/bgraph/pull/8">#8: Archive project</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="packaging-ecosystemsupply-chain">Packaging ecosystem/supply chain</h3>
<ul>
<li>Repo: Homebrew/.github
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/.github/pull/247">#247: actionlint: bump upload-sarif to v3.28.5</a></li>
<li><a href="https://github.com/Homebrew/.github/pull/253">#253: ci: switch to SSH signing</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: Homebrew/actions
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/actions/pull/645">#645: setup-commit-signing: move to SSH signing</a></li>
<li><a href="https://github.com/Homebrew/actions/pull/646">#646: setup-commit-signing: update README examples</a></li>
<li><a href="https://github.com/Homebrew/actions/pull/648">#648: ci: switch to SSH signing</a></li>
<li><a href="https://github.com/Homebrew/actions/pull/654">#654: setup-commit-signing: remove GPG signing support</a></li>
<li><a href="https://github.com/Homebrew/actions/pull/682">#682: Revert “*/README.md: note GitHub recommends pinning actions.”</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: Homebrew/brew
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/brew/pull/19230">#19230: ci: switch to SSH signing everywhere</a></li>
<li><a href="https://github.com/Homebrew/brew/pull/19217">#19217: dev-cmd: add brew verify</a></li>
<li><a href="https://github.com/Homebrew/brew/pull/19250">#19250: utils/pypi: warn when <code>pypi_info</code> fails due to missing sources</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: Homebrew/brew-pip-audit
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/brew-pip-audit/pull/161">#161: ci: ssh signing</a></li>
<li><a href="https://github.com/Homebrew/brew-pip-audit/pull/191">#191: add pr_title</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: Homebrew/brew.sh
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/brew.sh/pull/1125">#1125: _posts: add git signing post</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: Homebrew/homebrew-cask
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/homebrew-cask/pull/200760">#200760: ci: switch to SSH based signing</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: Homebrew/homebrew-command-not-found
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/Homebrew/homebrew-command-not-found/pull/213">#213: update-database: switch to SSH signing</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: PyO3/maturin
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/PyO3/maturin/pull/2429">#2429: ci: don’t enable sccache on tag refs</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: conda/schemas
<ul>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/conda/schemas/pull/76">#76: Add schema for publish attestation predicate</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: ossf/wg-securing-software-repos
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/ossf/wg-securing-software-repos/pull/57">#57: fix: replace job_workflow_ref with workflow_ref</a></li>
<li><a href="https://github.com/ossf/wg-securing-software-repos/pull/58">#58: chore: bump date in trusted-publishers-for-all-package-repositories.md</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypa/gh-action-pip-audit
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypa/gh-action-pip-audit/pull/54">#54: ci: zizmor fixes, add zizmor workflow</a></li>
<li><a href="https://github.com/pypa/gh-action-pip-audit/pull/57">#57: chore(ci): fix minor zizmor permissions findings</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypa/gh-action-pypi-publish
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypa/gh-action-pypi-publish/pull/347">#347: oidc-exchange: include environment in rendered claims</a></li>
<li><a href="https://github.com/pypa/gh-action-pypi-publish/pull/359">#359: deps: bump pypi-attestations to 0.0.26</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypa/packaging.python.org
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypa/packaging.python.org/pull/1803">#1803: simple-repository-api: bump, explain api-version</a></li>
<li><a href="https://github.com/pypa/packaging.python.org/pull/1808">#1808: simple-repository-api: clean up, add API history</a></li>
<li><a href="https://github.com/pypa/packaging.python.org/pull/1810">#1810: simple-repository-api: clean up PEP 658/PEP 714 bits</a></li>
<li><a href="https://github.com/pypa/packaging.python.org/pull/1859">#1859: guides: remove manual Sigstore steps from publishing guide</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypa/pip-audit
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypa/pip-audit/pull/875">#875: pyproject: drop setuptools from lint dependencies</a></li>
<li><a href="https://github.com/pypa/pip-audit/pull/878">#878: Remove two groups of resource leaks</a></li>
<li><a href="https://github.com/pypa/pip-audit/pull/879">#879: chore: prep 2.8.0</a></li>
<li><a href="https://github.com/pypa/pip-audit/pull/888">#888: PEP 751 support</a></li>
<li><a href="https://github.com/pypa/pip-audit/pull/890">#890: chore: prep 2.9.0</a></li>
<li><a href="https://github.com/pypa/pip-audit/pull/891">#891: chore: metadata cleanup</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypa/twine
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypa/twine/pull/1214">#1214: Update changelog for 6.1.0</a></li>
<li><a href="https://github.com/pypa/twine/pull/1229">#1229: deps: bump keyring to >=21.2.0</a></li>
<li><a href="https://github.com/pypa/twine/pull/1239">#1239: ci: apply fixes from zizmor</a></li>
<li><a href="https://github.com/pypa/twine/pull/1240">#1240: bugfix: utils: catch configparser.Error</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypi/pypi-attestations
<ul>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/pypi/pypi-attestations/pull/82">#82: Add <code>pypi-attestations verify pypi</code> CLI subcommand</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/83">#83: chore: prep 0.0.21</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/86">#86: cli: Support verifing <code>*.slsa.attestation</code> attestation files</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/87">#87: cli: Support friendlier syntax for <code>verify pypi</code> command</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/98">#98: Support local files in <code>verify pypi</code> subcommand</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/103">#103: Simplify test assets and include them in package</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/104">#104: Add API and CLI option for offline (no TUF refresh) verification</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/105">#105: Add CLI subcommand to convert Sigstore bundles to attestations</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/119">#119: Add pull request template</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/120">#120: Update license fields in pyproject.toml</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/128">#128: chore: prep v0.0.27</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/145">#145: chore: prep v0.0.28</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/151">#151: Fix lint and remove support for Python 3.9</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/150">#150: Add cooldown to dependabot updates</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/152">#152: Add zizmor to CI</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/153">#153: Remove unneeded permissions from zizmor workflow</a></li>
</ul>
</li>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypi/pypi-attestations/pull/94">#94: _cli: <code>make reformat</code></a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/99">#99: chore: prep v0.0.22</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/109">#109: bugfix: impl: require at least one of the source ref/sha extensions</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/110">#110: pypi_attestations: bump version to 0.0.23</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/114">#114: feat: add support for Google Cloud-based Trusted Publishers</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/115">#115: chore: prep for release v0.0.24</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/118">#118: chore: release: v0.0.25</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/122">#122: chore(ci): uvx gha-update</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/124">#124: fix: remove ultranormalization of distribution filenames</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/125">#125: chore: prep for release v0.0.26</a></li>
<li><a href="https://github.com/pypi/pypi-attestations/pull/127">#127: bugfix: compare distribution names by parsed forms</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: pypi/warehouse
<ul>
<li>By <a href="https://github.com/DarkaMaul">DarkaMaul</a>
<ul>
<li><a href="https://github.com/pypi/warehouse/pull/17463">#17463: Fix typo in PEP625 email</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17472">#17472: Add <code>published</code> column</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17512">#17512: Use zizmor from PyPI</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17513">#17513: Update workflows</a></li>
</ul>
</li>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/pypi/warehouse/pull/17391">#17391: docs: add details of how to verify provenance JSON files</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17438">#17438: Add archived badges to project’s settings page</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17484">#17484: Add blog post for archiving projects</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17532">#17532: Simplify archive/unarchive UI buttons</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17405">#17405: Improve error messages when a pending Trusted Publisher’s project name already exists</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17576">#17576: Check for existing Trusted Publishers before constraining existing one</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18168">#18168: Add workaround in dev docs for issue with OpenSearch image</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18221">#18221: chore(deps): bump pypi-attestations from 0.0.26 to 0.0.27</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18169">#18169: oidc: Refactor lookup strategies into single functions</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18338">#18338: oidc: fix bug when matching GitLab environment claims</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18884">#18884: Update URL for <code>pypi-attestations</code> repository</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18888">#18888: Update <code>pypi-attestations</code> to <code>v0.0.28</code></a></li>
</ul>
</li>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/pypi/warehouse/pull/17453">#17453: history: render project archival enter/exit events</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17498">#17498: integrity: refine Accept header handling</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17470">#17470: metadata: initial PEP 753 bits</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17514">#17514: docs/api: clean up Upload API docs slightly</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17571">#17571: profile: add archived projects section</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17716">#17716: docs: new and shiny storage limit docs</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/17913">#17913: requirements: bump pypi-attestations to 0.0.23</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18113">#18113: chore(docs): add social links for Mastodon and Bluesky</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18163">#18163: docs(dev): add meta docs on writing docs</a></li>
<li><a href="https://github.com/pypi/warehouse/pull/18164">#18164: docs: link to PyPI user docs more</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: python/peps
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/python/peps/pull/4356">#4356: Infra: Make PEP abstract extration more robust</a></li>
<li><a href="https://github.com/python/peps/pull/4432">#4432: PEP 792: Project status markers in the simple index</a></li>
<li><a href="https://github.com/python/peps/pull/4455">#4455: PEP 792: add Discussions-To link</a></li>
<li><a href="https://github.com/python/peps/pull/4457">#4457: PEP 792: clarify index API changes</a></li>
<li><a href="https://github.com/python/peps/pull/4463">#4463: PEP 792: additional review feedback</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/architecture-docs
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/sigstore/architecture-docs/pull/42">#42: specs: add algorithm-registry.md</a></li>
<li><a href="https://github.com/sigstore/architecture-docs/pull/44">#44: client-spec: reflow, fix more links</a></li>
<li><a href="https://github.com/sigstore/architecture-docs/pull/46">#46: PGI spec: fix Rekor/Fulcio spec links</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/community
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/community/pull/623">#623: Enforce branches up to date to avoid merging errors</a></li>
</ul>
</li>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/sigstore/community/pull/582">#582: sigstore: add myself to architecture-doc-team</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/cosign
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/cosign/pull/4111">#4111: cmd/cosign/cli: fix typo in ignoreTLogMessage</a></li>
<li><a href="https://github.com/sigstore/cosign/pull/4050">#4050: Remove SHA256 assumption in sign-blob/verify-blob</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/fulcio
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/fulcio/pull/1938">#1938: Allow configurable client signing algorithms</a></li>
<li><a href="https://github.com/sigstore/fulcio/pull/1959">#1959: Proof of Possession agility</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/gh-action-sigstore-python
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/sigstore/gh-action-sigstore-python/pull/160">#160: ci: cleanup, fix zizmor findings</a></li>
<li><a href="https://github.com/sigstore/gh-action-sigstore-python/pull/161">#161: README: add a notice about whether this action is needed</a></li>
<li><a href="https://github.com/sigstore/gh-action-sigstore-python/pull/165">#165: chore: hash-pin everything</a></li>
<li><a href="https://github.com/sigstore/gh-action-sigstore-python/pull/183">#183: chore: prep 3.0.1</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/protobuf-specs
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/protobuf-specs/pull/572">#572: protos/PublicKeyDetails: add compatibility algorithms using SHA256</a></li>
</ul>
</li>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/sigstore/protobuf-specs/pull/467">#467: use Pydantic dataclasses for Python bindings</a></li>
<li><a href="https://github.com/sigstore/protobuf-specs/pull/468">#468: pyproject: prep 0.3.5</a></li>
<li><a href="https://github.com/sigstore/protobuf-specs/pull/595">#595: docs: rm algorithm-registry.md</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/rekor
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/rekor/pull/2429">#2429: pkg/api: better logs when algorithm registry rejects a key</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/rekor-monitor
<ul>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/685">#685: Fix Makefile and README</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/689">#689: Make CLI args for configuration path/string mutually exclusive</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/688">#688: Add support for CT log entries with Precertificates</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/695">#695: Fetch public keys using TUF</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/705">#705: Initial support for Rekor v2</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/729">#729: Handle sharding of Rekor v2 log while monitor runs</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/752">#752: Use <code>int64</code> for index types</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/751">#751: Add identity monitoring for Rekor v2</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/827">#827: Add cooldown to dependabot updates</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/828">#828: Update codeql-action</a></li>
</ul>
</li>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/717">#717: ci: wrap inputs.config in ct_reusable_monitoring</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/718">#718: doc: correct usage of ct log monitoring workflow</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/724">#724: pkg/rekor: handle signals inside long op GetEntriesByIndexRange</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/723">#723: Deduplicate ct/rekor monitoring reusable workflows</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/725">#725: Refactor IdentitySearch logic between ct and rekor</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/726">#726: Deduplicate ct and rekor monitors</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/727">#727: Fix once behaviour</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/730">#730: cmd/rekor_monitor: accept custom TUF</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/736">#736: pkg/notifications: make Notifications more customazible</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/739">#739: Add a few tests for the main monitor loop</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/742">#742: internal/cmd/common_test: fix TestMonitorLoop_BasicExecution</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/741">#741: Add config validation</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/743">#743: Fix monitor loop behaviour when using once without a prev checkpoint</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/738">#738: Report failed entries</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/745">#745: internal/cmd: fix common tests after merging</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/740">#740: Split the consistency check and the checkpoint writing</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/746">#746: cmd: fix WriteCheckpointFn when no previous checkpoint</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/748">#748: Small refactoring</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/749">#749: internal/cmd: Use interface instead of callbacks</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/750">#750: internal/cmd: remove unused MonitorLoopParams struct</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/763">#763: pkg/util/file: write only one checkpoint</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/764">#764: Add trusted CAs for filtering matched identities</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/771">#771: Fix bug with missing entries when regex were used</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/773">#773: pkg/identity: simplify CreateMonitoredIdentities function</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/770">#770: Check Certificate chain in CTLogs</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/777">#777: Refactor IdentitySearch args</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/776">#776: ci: add release workflow</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/778">#778: Parsable output</a></li>
<li><a href="https://github.com/sigstore/rekor-monitor/pull/786">#786: Improve README by explaining config file</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/rekor-tiles
<ul>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/sigstore/rekor-tiles/pull/479">#479: Make <code>verifier</code> pkg public</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/sigstore
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/sigstore/pull/1981">#1981: pkg/signature: fix RSA PSS 3072 key size in algorithm registry</a></li>
<li><a href="https://github.com/sigstore/sigstore/pull/2001">#2001: pkg/signature: expose Algorithm Details information</a></li>
<li><a href="https://github.com/sigstore/sigstore/pull/2014">#2014: Implement default signing algorithms based on the key type</a></li>
<li><a href="https://github.com/sigstore/sigstore/pull/2037">#2037: pkg/signature: add P384/P521 compatibility algo to algorithm registry</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/sigstore-conformance
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/sigstore/sigstore-conformance/pull/176">#176: handle different certificate fields correctly</a></li>
<li><a href="https://github.com/sigstore/sigstore-conformance/pull/199">#199: action: bump cpython-release-tracker</a></li>
<li><a href="https://github.com/sigstore/sigstore-conformance/pull/200">#200: README: prep for v0.0.17 release</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/sigstore-go
<ul>
<li>By <a href="https://github.com/facutuesca">facutuesca</a>
<ul>
<li><a href="https://github.com/sigstore/sigstore-go/pull/506">#506: Update GetSigningConfig to use <code>signing_config.v0.2.json</code></a></li>
</ul>
</li>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/sigstore/sigstore-go/pull/433">#433: pkg/root: fix typo in nolint annotation</a></li>
<li><a href="https://github.com/sigstore/sigstore-go/pull/424">#424: Use default Verifier for the public key contained in a certificate (closes #74)</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/sigstore-python
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/sigstore/sigstore-python/pull/1283">#1283: ci: fix offline tests on ubuntu-latest</a></li>
<li><a href="https://github.com/sigstore/sigstore-python/pull/1293">#1293: ci: remove dependabot + gomod, always fetch latest</a></li>
<li><a href="https://github.com/sigstore/sigstore-python/pull/1310">#1310: docs: clarify Verifier APIs</a></li>
<li><a href="https://github.com/sigstore/sigstore-python/pull/1450">#1450: chore(deps): bump rfc3161-client to >= 1.0.3</a></li>
<li><a href="https://github.com/sigstore/sigstore-python/pull/1451">#1451: Backport #1450 to 3.6.x</a></li>
<li><a href="https://github.com/sigstore/sigstore-python/pull/1452">#1452: chore: prep 3.6.4</a></li>
<li><a href="https://github.com/sigstore/sigstore-python/pull/1453">#1453: chore: forward port changelog from 3.6.4</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: sigstore/sigstore-rekor-types
<ul>
<li>By <a href="https://github.com/dguido">dguido</a>
<ul>
<li><a href="https://github.com/sigstore/sigstore-rekor-types/pull/219">#219: Upgrade to Python 3.9 and update to Rekor v1.4.0</a></li>
</ul>
</li>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/sigstore/sigstore-rekor-types/pull/169">#169: chore(ci): pin everywhere, drop perms</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: synacktiv/DepFuzzer
<ul>
<li>By <a href="https://github.com/thomas-chauchefoin-tob">thomas-chauchefoin-tob</a>
<ul>
<li><a href="https://github.com/synacktiv/DepFuzzer/pull/11">#11: Switch boolean args to flags</a></li>
<li><a href="https://github.com/synacktiv/DepFuzzer/pull/12">#12: Use MX records to validate email domains</a></li>
<li><a href="https://github.com/synacktiv/DepFuzzer/pull/13">#13: Fix empty author_email handling for PyPI</a></li>
<li><a href="https://github.com/synacktiv/DepFuzzer/pull/15">#15: Detect disposable providers in maintainer emails</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: wolfv/ceps
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/wolfv/ceps/pull/5">#5: add cep for sigstore</a></li>
<li><a href="https://github.com/wolfv/ceps/pull/6">#6: sigstore-cep: rework Discussion and Future Work sections</a></li>
<li><a href="https://github.com/wolfv/ceps/pull/7">#7: Sigstore CEP: address additional feedback</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="others">Others</h3>
<ul>
<li>Repo: AzureAD/microsoft-authentication-extensions-for-python
<ul>
<li>By <a href="https://github.com/DarkaMaul">DarkaMaul</a>
<ul>
<li><a href="https://github.com/AzureAD/microsoft-authentication-extensions-for-python/pull/144">#144: Add missing import in token_cache_sample</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: SchemaStore/schemastore
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/SchemaStore/schemastore/pull/4635">#4635: github-workflow: workflow_call.secrets.*.required is not required</a></li>
<li><a href="https://github.com/SchemaStore/schemastore/pull/4637">#4637: github-workflow: trigger types can be an array or a scalar string</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: google/gvisor
<ul>
<li>By <a href="https://github.com/ret2libc">ret2libc</a>
<ul>
<li><a href="https://github.com/google/gvisor/pull/12325">#12325: usertrap: disable syscall patching when ptraced</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: oli-obk/cargo_metadata
<ul>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/oli-obk/cargo_metadata/pull/295">#295: Update <code>cargo-util-schemas</code> to version 0.8.1</a></li>
<li><a href="https://github.com/oli-obk/cargo_metadata/pull/305">#305: Proposed <code>-Zbuild-dir</code> fix</a></li>
<li><a href="https://github.com/oli-obk/cargo_metadata/pull/304">#304: Add newtype wrapper</a></li>
<li><a href="https://github.com/oli-obk/cargo_metadata/pull/307">#307: Bump version</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: ossf/alpha-omega
<ul>
<li>By <a href="https://github.com/woodruffw">woodruffw</a>
<ul>
<li><a href="https://github.com/ossf/alpha-omega/pull/454">#454: PyPI: record 2024-12</a></li>
<li><a href="https://github.com/ossf/alpha-omega/pull/468">#468: engagements: add PyCA</a></li>
<li><a href="https://github.com/ossf/alpha-omega/pull/467">#467: pypi: add January 2025 update (#2025)</a></li>
<li><a href="https://github.com/ossf/alpha-omega/pull/478">#478: engagements: update PyPI and PyCA for February 2025</a></li>
<li><a href="https://github.com/ossf/alpha-omega/pull/487">#487: PyPI, PyCA: March 2025 updates</a></li>
<li><a href="https://github.com/ossf/alpha-omega/pull/499">#499: PyPI, PyCA: April 2025 updates</a></li>
</ul>
</li>
</ul>
</li>
<li>Repo: rustsec/advisory-db
<ul>
<li>By <a href="https://github.com/DarkaMaul">DarkaMaul</a>
<ul>
<li><a href="https://github.com/rustsec/advisory-db/pull/2169">#2169: Protobuf DoS</a></li>
</ul>
</li>
<li>By <a href="https://github.com/smoelius">smoelius</a>
<ul>
<li><a href="https://github.com/rustsec/advisory-db/pull/2289">#2289: Withdraw RUSTSEC-2022-0044</a></li>
</ul>
</li>
</ul>
</li>
</ul>Published on Citation Needed: "Issue 100 – Freedom of all kinds is worth fighting for" - Molly White's activity feed697be17a498c9cae1763aaf12026-01-29T22:38:50.000Z<article class="entry h-entry hentry"><header><div class="description">Published an issue of <a href="https://www.citationneeded.news/"><i>Citation Needed</i></a>: </div><h2 class="p-name"><a class="u-syndication" href="https://www.citationneeded.news/issue-100" rel="syndication">Issue 100 – Freedom of all kinds is worth fighting for </a></h2></header><div class="content e-content"><div class="media-wrapper"><a href="https://www.citationneeded.news/issue-100"><img src="https://www.citationneeded.news/content/images/size/w2000/format/webp/2026/01/issue-100.jpg" alt="ICE agents shoot projectiles at protesters in Minneapolis on January 24. The photo has been overlaid with an upside down American flag."/></a></div><div class="p-summary"><p>As masked agents execute people and terrorize communities, crypto executives who spent years posting about freedom fall conspicuously silent — except when writing checks for the politicians enabling it</p></div></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <a href="https://www.citationneeded.news/issue-100"><time class="dt-published" datetime="2026-01-29T22:38:50+00:00" title="January 29, 2026 at 10:38 PM UTC">January 29, 2026 at 10:38 PM UTC</time>. </a></div><div class="social-links"> <span>Also posted to:</span><a class="social-link u-syndication mastodon" href="https://hachyderm.io/@molly0xfff/115980722734784145" title="Mastodon" rel="syndication">Mastodon</a><a class="social-link u-syndication bluesky" href="https://bsky.app/profile/molly.wiki/post/3mdlt5xpmzc22" 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/feed/tag/crypto" title="See all feed posts tagged "crypto"" rel="category tag">crypto</a>, <a class="tag p-category" href="https://www.mollywhite.net/feed/tag/crypto_lobby" title="See all feed posts tagged "crypto lobby"" rel="category tag">crypto lobby</a>, <a class="tag p-category" href="https://www.mollywhite.net/feed/tag/trump_administration" title="See all feed posts tagged "Trump administration"" rel="category tag">Trump administration</a>.</div></div></footer></article>Book Review: The Players Act 1 by Amy Sparkes ★★⯪☆☆ - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=664462026-01-29T12:34:04.000Z<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/02/the-players-act-1.jpg" alt="Book cover featuring illustrated actors." width="200" class="alignleft size-full wp-image-66448"/>
<p>So! Much! Melodrama!</p>
<p>This is a gently funny (and slightly tragic) romp with a band of travelling <del>vagrants</del> actors as they attempt to ply their renditions of Shakespeare to an indifferent 1700ish audience. There's a lot of charm to the characters and the plot is relatively straightforward.</p>
<p>The characters are a <em>bit</em> one-note. The baddie never <em>actually</em> twirls his moustache - but you'll instantly picture him doing it every time he appears. The others very much stay in their lane; the feisty woman who would rather wear trousers, the wide-eyed idealist, the grumpy father. It's rather like they're stock <i lang="it">comedia dell'arte</i> tropes come to life.</p>
<p>While there are some lovely lines (and excellent swearing), the story meanders back and forth a bit too much for my liking. I'm possibly not the target audience as I guess this is aimed at the older teen crowd.</p>
<p>I appreciate the book being made available without DRM. How refreshing to pay for a book and receive an unencumbered ePub; no need to liberate it from the clutches of Adobe!</p>
Building cryptographic agility into Sigstore - Trail of Bits Bloghttps://blog.trailofbits.com/2026/01/29/building-cryptographic-agility-into-sigstore/2026-01-29T12:00:00.000Z<p>Software signatures carry an invisible expiration date. The container image or firmware you sign today might be deployed for 20 years, but the cryptographic signature protecting it may become untrustworthy within 10 years. SHA-1 certificates become worthless, weak RSA keys are banned, and quantum computers may crack today’s elliptic curve cryptography. The question isn’t whether our current signatures will fail, but whether we’re prepared for when they do.</p>
<p>Sigstore, an open-source ecosystem for software signing, recognized this challenge early but initially chose security over flexibility by adopting new cryptographic algorithms as older ones became obsolete. By hard coding ECDSA with P-256 curves and SHA-256 throughout its infrastructure, Sigstore avoided the dangerous pitfalls that have plagued other crypto-agile systems. This conservative approach worked well during early adoption, but as Sigstore’s usage grew, the rigidity that once protected it began to restrict its utility.</p>
<p>Over the past two years, Trail of Bits has collaborated with the Sigstore community to systematically address the limitations of aging cryptographic signatures. Our work established a centralized algorithm registry in the Protobuf specifications to serve as a single source of truth. Second, we updated Rekor and Fulcio to accept configurable algorithm restrictions. And finally, we integrated these capabilities into Cosign, allowing users to select their preferred signing algorithm when generating ephemeral keys. We also developed Go implementations of post-quantum algorithms LMS and ML-DSA, demonstrating that the new architecture can accommodate future cryptographic standards. Here is what motivated these changes, what security considerations shaped our approach, and how to use the new functionality.</p>
<h2 id="sigstores-cryptographic-constraints">Sigstore’s cryptographic constraints</h2>
<p>Sigstore hard codes ECDSA with P-256 curves and SHA-256 throughout most of its ecosystem. This rigidity is a deliberate design choice. From Fulcio certificate issuance to Rekor transparency logs to Cosign workflows, most steps default to this same algorithm. Cryptographic agility has historically led to serious security vulnerabilities, and focusing on a limited set of algorithms reduces the chance of something going wrong.</p>
<p>This conservative approach, however, has created challenges as the ecosystem has matured. Various organizations and users have vastly different requirements that Sigstore’s rigid approach cannot accommodate. Here are some examples:</p>
<ul>
<li><strong>Compliance-driven organizations</strong> might need NIST-standard algorithms to meet regulatory requirements.</li>
<li><strong>Open-source maintainers</strong> may want to sign artifacts without making cryptographic decisions, relying on secure defaults from the public Sigstore instance.</li>
<li><strong>Security-conscious enterprises</strong> may want to deploy internal Sigstore instances using only post-quantum cryptography.</li>
</ul>
<p>Furthermore, software artifacts remain in use for decades, meaning today’s signatures must stay verifiable far into the future, and the cryptographic algorithm used today might not be secure 10 years from now.</p>
<p>These challenges can be addressed only if Sigstore allows for a certain degree of cryptographic agility. The goal is to enable controlled cryptographic flexibility without repeating the security issues that have affected other crypto-agile systems. To address this, the Sigstore community has developed a <a href="https://docs.google.com/document/d/18vTKFvTQdRt3OGz6Qd1xf04o-hugRYSup-1EAOWn7MQ/edit?tab=t.0#heading=h.op2lvfrgiugr">design document</a> outlining how to introduce cryptographic agility while maintaining strong security guarantees.</p>
<h2 id="the-dangers-of-cryptographic-flexibility">The dangers of cryptographic flexibility</h2>
<p>The most infamous example of problems caused by cryptographic flexibility is <a href="https://jwt.io/introduction">the JWT</a> <code>alg:</code> <code>none</code> vulnerability, where some JWT libraries treated tokens signed with the <code>none</code> algorithm as valid tokens, allowing anyone to forge arbitrary tokens and “sign” whatever payload they wanted. Even more subtle is the <a href="https://portswigger.net/web-security/jwt/algorithm-confusion">RSA/HMAC confusion attack in JWT</a>, where a mismatch between what kind of algorithm a server expects and what it receives allows anyone with knowledge of the RSA public key to forge tokens that pass verification.</p>
<p>The fundamental problem in both cases is in-band algorithm signaling, which allows the data to specify how it should be protected. This creates an opportunity for attackers to manipulate the algorithm choice to their advantage. As the cryptographic community has learned through painful experience, cryptographic agility introduces significant complexity, leading to more code and increased potential attack vectors.</p>
<h2 id="the-solution-controlled-cryptographic-flexibility">The solution: Controlled cryptographic flexibility</h2>
<p>Instead of allowing users to mix and match any algorithms they want, Sigstore introduced predefined algorithm suites, which are complete packages that specify exactly which cryptographic components work together.</p>
<p>For example, <code>PKIX_ECDSA_P256_SHA_256</code> not only includes the signing algorithm (ECDSA P-256), but also mandates SHA-256 for hashing. A <code>PKIX_ECDSA_P384_SHA_384</code> suite pairs ECDSA P-384 with SHA-384, and <code>PKIX_ED25519</code> uses Ed25519 and SHA-512. Users can choose between these suites, but they can’t create dangerous combinations, such as ECDSA P-384 with MD5.</p>
<p>Critically, the choice of which algorithm to use comes from out-of-band negotiation, meaning it’s determined by configuration or policy, not by the data being signed. This prevents the in-band signaling attacks that have plagued other systems.</p>
<h2 id="the-implementation">The implementation</h2>
<p>To enable cryptographic agility across the Sigstore ecosystem, we needed to make coordinated changes that would work together seamlessly. Cryptography is used in several places within the Sigstore ecosystem; however, we primarily focused on enabling clients to change the signing algorithm used to sign and verify artifacts, as this would have a significant impact on end users. We tackled this change in three phases.</p>
<h3 id="phase-1-establishing-common-ground">Phase 1: Establishing common ground</h3>
<p>We introduced a centralized <a href="https://github.com/sigstore/protobuf-specs/blob/966b43d006e7fc938b30724933af34c8e351f2a1/protos/sigstore_common.proto#L46-L129">algorithm registry</a> in the Protobuf specifications that defines all <a href="https://github.com/sigstore/sigstore/blob/1e63a2159e71d968a5fa46215280103844797ee8/pkg/signature/algorithm_registry.go#L154">allowed algorithms</a> and their details. We also implemented <a href="https://github.com/sigstore/sigstore/blob/1e63a2159e71d968a5fa46215280103844797ee8/pkg/signature/algorithm_registry.go#L238-L298">default mappings</a> from key types to signing algorithms (e.g., ECDSA P-256 keys automatically use ECDSA P-256 + SHA-256), eliminating ambiguity and providing a single source of truth for all Sigstore components.</p>
<h3 id="phase-2-service-level-updates">Phase 2: Service-level updates</h3>
<p>We updated <a href="https://github.com/sigstore/rekor/pull/1974">Rekor</a> and <a href="https://github.com/sigstore/fulcio/pull/1938">Fulcio</a> with a new <code>--client-signing-algorithms</code> flag that lets deployments specify which algorithms they accept, enabling custom restrictions like Ed25519-only or future post-quantum-only deployments. We also <a href="https://github.com/sigstore/fulcio/pull/1959">fixed Fulcio</a> to use proper hash algorithms for each key type (SHA-384 for ECDSA P-384, etc.) instead of defaulting everything to SHA-256.</p>
<h3 id="phase-3-client-integration">Phase 3: Client integration</h3>
<p>We updated Cosign to support multiple algorithms by <a href="https://github.com/sigstore/cosign/pull/4050">removing hard-coded SHA-256</a> usage and adding a <a href="https://github.com/sigstore/cosign/pull/3497"><code>--signing-algorithm</code></a> flag for generating different ephemeral key types. Currently available in <code>cosign sign-blob</code> and <code>cosign verify-blob</code>, these changes let users bring their own keys of any supported type and easily select their preferred cryptographic algorithm when ephemeral keys are used. Other clients implementing the Sigstore specification can choose which set of algorithms to use, as long as it is a subset of the allowed algorithms listed in the algorithm registry.</p>
<h3 id="validation-proving-it-works">Validation: Proving it works</h3>
<p>To demonstrate the flexibility of our new architecture, we developed HashEdDSA (Ed25519ph) support in both <a href="https://github.com/sigstore/rekor/pull/1945">Rekor</a> and <a href="https://github.com/sigstore/sigstore/pull/1595">the Sigstore Go library</a> and created Go implementations of post-quantum algorithms <a href="https://github.com/trailofbits/lms-go">LMS</a> and <a href="https://github.com/trailofbits/ml-dsa">ML-DSA</a>. This work proved that our modular architecture can accommodate diverse cryptographic algorithms and provides a solid foundation for future additions, including post-quantum cryptography.</p>
<h2 id="cryptographic-flexibility-in-action">Cryptographic flexibility in action</h2>
<p>Let’s see this cryptographic flexibility in action by setting up a custom Sigstore deployment. We’ll configure a private Rekor instance that accepts only ECDSA P-521 with SHA-512 and RSA-4096 with SHA-256, by using the <code>--client-signing-algorithms</code> flag, demonstrating both algorithm restriction and the new Cosign capabilities.</p>
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">~/rekor$ git diff
</span></span><span class="line"><span class="cl">diff --git a/docker-compose.yml b/docker-compose.yml
</span></span><span class="line"><span class="cl">index 3e5f4c3..93e0d10 <span class="m">100644</span>
</span></span><span class="line"><span class="cl">--- a/docker-compose.yml
</span></span><span class="line"><span class="cl">+++ b/docker-compose.yml
</span></span><span class="line"><span class="cl">@@ -120,6 +120,7 @@ services:
</span></span><span class="line"><span class="cl"> <span class="s2">"--enable_stable_checkpoint"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"--search_index.storage_provider=mysql"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"--search_index.mysql.dsn=test:zaphod@tcp(mysql:3306)/test"</span>,
</span></span><span class="line"><span class="cl">+ <span class="s2">"--client-signing-algorithms=ecdsa-sha2-512-nistp521,rsa-sign-pkcs1-4096-sha256"</span>,
</span></span><span class="line"><span class="cl"> <span class="c1"># Uncomment this for production logging</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># "--log_type=prod",</span>
</span></span><span class="line"><span class="cl"> <span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ docker compose up -d</span></span></code></pre>
</figure>
<p>Let’s create the artifact and use Cosign to sign it:</p>
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ <span class="nb">echo</span> <span class="s2">"Trail of Bits & Sigstore"</span> > msg.txt
</span></span><span class="line"><span class="cl">$ ./cosign sign-blob --bundle cosign.bundle --signing-algorithm<span class="o">=</span>ecdsa-sha2-512-nistp521 --rekor-url http://localhost:3000 msg.txt
</span></span><span class="line"><span class="cl">Retrieving signed certificate...
</span></span><span class="line"><span class="cl">Successfully verified SCT...
</span></span><span class="line"><span class="cl">Using payload from: msg.txt
</span></span><span class="line"><span class="cl">tlog entry created with index: <span class="m">111111111</span>
</span></span><span class="line"><span class="cl">Wrote bundle to file cosign.bundle
</span></span><span class="line"><span class="cl">qzbCtK4WuQeoeZzGP1111123+...+j7NjAAAAAAAA<span class="o">==</span></span></span></code></pre>
</figure>
<p>This last command performs a few steps:</p>
<ol>
<li>Generates an ephemeral private/public ECDSA P-521 key pair and gets the SHA-512 hash of the artifact (<code>--signing-algorithm=ecdsa-sha2-512-nistp521</code>)</li>
<li>Uses the ECDSA P-521 key to request a certificate to Fulcio</li>
<li>Signs the hash with the certificate</li>
<li>Submits the artifact’s hash, the certificate, and some extra data to our local instance of Rekor (<code>--rekor-url http://localhost:3000</code>)</li>
<li>Saves everything into the <code>cosign.bundle</code> file (<code>--bundle cosign.bundle</code>)</li>
</ol>
<p>We can verify the data in the bundle to ensure ECDSA P-521 was actually used (with the right hash function):</p>
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ jq -C <span class="s1">'.messageSignature'</span> cosign.bundle
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"messageDigest"</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"algorithm"</span>: <span class="s2">"SHA2_512"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"digest"</span>: <span class="s2">"WIjb9UuEBgdSxhRMoz+Zux4ig8kWY...+65L6VSPCKCtzA=="</span>
</span></span><span class="line"><span class="cl"> <span class="o">}</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"signature"</span>: <span class="s2">"MIGIAkIBRrn.../zgwlBT6g=="</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ jq -r <span class="s1">'.verificationMaterial.certificate.rawBytes'</span> cosign.bundle <span class="p">|</span> base64 -d <span class="p">|</span> openssl x509 -text -noout -in /dev/stdin <span class="p">|</span> grep -A <span class="m">6</span> <span class="s2">"Subject Public Key Info"</span>
</span></span><span class="line"><span class="cl"> Subject Public Key Info:
</span></span><span class="line"><span class="cl"> Public Key Algorithm: id-ecPublicKey
</span></span><span class="line"><span class="cl"> Public-Key: <span class="o">(</span><span class="m">521</span> bit<span class="o">)</span>
</span></span><span class="line"><span class="cl"> pub:
</span></span><span class="line"><span class="cl"> 04:01:36:90:6c:d5:53:5f:8d:4b:c6:2a:13:36:69:
</span></span><span class="line"><span class="cl"> 31:54:e3:2d:92:e0:bd:d5:77:35:37:62:cd:6a:4d:
</span></span><span class="line"><span class="cl"> 9f:32:83:97:a7:0d:4e:48:73:fe:3c:a2:0f:f2:3d:</span></span></code></pre>
</figure>
<p>Now let’s try a different key type to see if it’s rejected by Rekor. To generate a different key type, we just need to switch the value of <code>--signing-algorithm</code> in Cosign:</p>
<figure class="highlight">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ ./cosign sign-blob --bundle cosign.bundle --signing-algorithm<span class="o">=</span>ecdsa-sha2-256-nistp256 --rekor-url http://localhost:3000 msg.txt
</span></span><span class="line"><span class="cl">Generating ephemeral keys...
</span></span><span class="line"><span class="cl">Retrieving signed certificate...
</span></span><span class="line"><span class="cl">Successfully verified SCT...
</span></span><span class="line"><span class="cl">Using payload from: msg.txt
</span></span><span class="line"><span class="cl">Error: signing msg.txt: <span class="o">[</span>POST /api/v1/log/entries<span class="o">][</span>400<span class="o">]</span> createLogEntryBadRequest <span class="o">{</span><span class="s2">"code"</span>:400,<span class="s2">"message"</span>:<span class="s2">"error processing entry: entry algorithms are not allowed"</span><span class="o">}</span>
</span></span><span class="line"><span class="cl">error during <span class="nb">command</span> execution: signing msg.txt: <span class="o">[</span>POST /api/v1/log/entries<span class="o">][</span>400<span class="o">]</span> createLogEntryBadRequest <span class="o">{</span><span class="s2">"code"</span>:400,<span class="s2">"message"</span>:<span class="s2">"error processing entry: entry algorithms are not allowed"</span><span class="o">}</span></span></span></code></pre>
</figure>
<p>As we can see, Rekor did not allow Cosign to save the entry (<code>entry algorithms are not allowed</code>), as <code>ecdsa-sha2-256-nistp256</code> was not part of the list of algorithms allowed through the <code>--client-signing-algorithms</code> flag used when starting the Rekor instance.</p>
<h2 id="future-proofing-sigstore">Future-proofing Sigstore</h2>
<p>The changes that Trail of Bits has implemented alongside the Sigstore community allow organizations to use different signing algorithms while maintaining the same security model that made Sigstore successful.</p>
<p>Sigstore now supports algorithm suites from ECDSA P-256 to Ed25519 to RSA variants, with a centralized registry ensuring consistency across deployments. Organizations can configure their instances to accept only specific algorithms, whether for compliance requirements or post-quantum preparation.</p>
<p>The foundation is now in place for future algorithm additions. As cryptographic standards evolve and new algorithms become available, Sigstore can adopt them through the same controlled process we’ve established. Software signatures created today will remain verifiable as the ecosystem adapts to new cryptographic realities.</p>
<p>Want to dig deeper? Check out our <a href="https://github.com/trailofbits/lms-go">LMS</a> and <a href="https://github.com/trailofbits/ml-dsa">ML-DSA</a> Go implementations for post-quantum cryptography, or run <code>--help</code> on Rekor, Fulcio, and Cosign to explore the new algorithm configuration options. If you’re looking to modernize your project’s cryptography to current standards, <a href="https://www.trailofbits.com/services/cryptography">Trail of Bits’ cryptography consulting services</a> can help you get on the right path.</p>
<p>We would like to thank Google, OpenSSF, and Hewlett-Packard for having funded some of this work. Trail of Bits continues to contribute to the Sigstore ecosystem as part of our ongoing commitment to strengthening open-source security infrastructure.</p>Are there any open APIs left? - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=618072026-01-28T12:34:01.000Z<p>One of the dreams of Web 2.0 was that website would speak unto website. An "Application Programming Interface" (API) would give programmatic access to structured data, allowing services to seamlessly integrate content from each other. Users would be able to quickly grab data from multiple sources and use them for their own purposes. No registration or API keys, no tedious EULAs or meetings. Just pure synergy!</p>
<p>Is that dream dead? If so, what killed it?</p>
<p>A decade ago, I posted a plea looking for <a href="https://shkspr.mobi/blog/2014/04/wanted-simple-apis-without-authentication/">Easy APIs Without Authentication</a> with a <a href="https://shkspr.mobi/blog/2016/05/easy-apis-without-authentication/">follow up post two years later</a>. I wanted some resources that students could use with minimal fuss. Are any of the APIs from 10 years ago still alive?</p>
<h2 id="alive"><a href="https://shkspr.mobi/blog/2026/01/are-there-any-open-apis-left/#alive">Alive</a></h2>
<p>These ones are still around:</p>
<ul style="list-style-type:'✅';">
<li><a href="https://api.wikimedia.org/wiki/Core_REST_API">Wikipedia</a> - Yes! Still going strong.
</li><li><a href="https://data.police.uk/">Police.uk</a> - Yes! After a <a href="https://data.police.uk/docs/authentication/">brief dalliance with API registration</a>, it is now back to being completely free and open.
</li><li><a href="https://www.googleapis.com/books/v1/volumes?q=isbn:9781408864401">Google Books ISBN</a> - Yes! Obviously Google have forgotten it exists; otherwise it would have been killed off by now!
</li><li><a href="https://itunes.apple.com/search?term=beatles&entity=musicVideo">iTunes Lookup</a> - Yes! Possibly the only thing Apple don't charge a premium for.
</li><li><a href="https://pokeapi.co/">Pokémon API</a> - and still receiving frequent updates.
</li><li><a href="https://musicbrainz.org/doc/MusicBrainz_API">MusicBrainz</a> - this Internet stalwart will never die.
</li><li><a href="http://open-notify.org/">Open Notify</a> - a collection of space APIs, although the code hasn't been updated in ages.
</li></ul>
<h2 id="dead"><a href="https://shkspr.mobi/blog/2026/01/are-there-any-open-apis-left/#dead">Dead</a></h2>
<p>These have shuffled off this mortal coil:</p>
<ul style="list-style-type:'❌';">
<li>BBC Radio 1 - No.
</li><li>Twitter URL statistics - LOLSOB No.
</li><li>Star Wars API - No.
</li><li>British National Bibliography - No. Dead due, I think to the British Library's cyber attack.
</li><li><a href="https://web.archive.org/web/20160511215743/http://api.football-data.org/code_samples">Football Data</a> - gone.
</li></ul>
<h2 id="api-key-required"><a href="https://shkspr.mobi/blog/2026/01/are-there-any-open-apis-left/#api-key-required">API Key Required</a></h2>
<p>These are still alive, but you either need to pay or register to use them:</p>
<ul style="list-style-type:'🔑';">
<li>Google Location
</li><li><a href="https://api.spotify.com/v1/search?q=bowie&type=artist">Spotify</a>
</li><li><a href="https://www.omdbapi.com/?t=star%20wars&y=&plot=short&r=json">OpenMovieDB</a>
</li><li><a href="https://docs.openaq.org/using-the-api/api-key">Open Air Quality</a>
</li></ul>
<h2 id="what-happened"><a href="https://shkspr.mobi/blog/2026/01/are-there-any-open-apis-left/#what-happened">What Happened?</a></h2>
<p>Something something … enshittification … blah blah … zero interest rate phenomenon … yadda yadda our incredible journey …</p>
<p>But back in the land of rationality, I've had a lots of experiences running APIs and helping people who run them. The closure and lockdown of APIs usually comes down to one or more of the following.</p>
<p>APIs cost money to run. Yes, even the static ones have a non-zero cost. That's fine if you're prepared to endless subsidise them - but it is hard to justify if there's no return on investment. Anyway, who is using all this bandwidth? Which leads on to:</p>
<p>Lack of analytics. Yes, I know tracking is the devil, but it is hard to build a service if you don't know who is using it. Sure, you can see traffic, but you can't tell if it is useful to the end consumer, or what value you can share. There's no way to communicate with an anonymous consumer. Which, of course, takes us to the next barrier:</p>
<p>Communication is key. If you need to change your API, there's no way to tell users that a change is coming. That might be the announcement of a deprecation, an outage, or an enhancement. You can try smuggling error messages into your responses and hoping someone notices a failing service somewhere - but it's much easier to email everyone who has an API key. And you know what else keys are good for?</p>
<p>Stopping abuse. It'd be nice if everyone played nice online; but some people are raging arseholes. Being able to throttle bad actors (figuratively or literally) is a desirable feature. On a resource constrained service, you sometimes have to put rules in place.</p>
<p>Still, if you know of any good open APIs which don't require registration, and that you think will survive until 2036, please drop a link in the comments.</p>