<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss/styles.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Brioche Blog</title><description>The official blog of Brioche.</description><link>https://brioche.dev</link><item><title>Brioche v0.1.8: Preparing for the future</title><link>https://brioche.dev/blog/brioche-v0-1-8</link><guid isPermaLink="true">https://brioche.dev/blog/brioche-v0-1-8</guid><pubDate>Sat, 30 May 2026 07:19:57 GMT</pubDate><content:encoded>&lt;p&gt;Brioche v0.1.8 is a pretty small release overall, with a few quality-of-life improvements, plus some enhancements to prepare for some future changes.&lt;/p&gt;
&lt;p&gt;To get right into it, you can run &lt;code&gt;brioche self-update&lt;/code&gt; to upgrade, or check the &lt;a href=&quot;/docs/installation&quot;&gt;installation docs&lt;/a&gt; if you don&apos;t have Brioche installed yet. You can also take a look at &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.8&quot;&gt;the release notes&lt;/a&gt;, if that&apos;s more your speed.&lt;/p&gt;
&lt;p&gt;Oh, and also a &lt;a href=&quot;#reader-support-for-new-cache-archive-tag&quot;&gt;&lt;strong&gt;PSA about upcoming &lt;code&gt;brioche-packages&lt;/code&gt; stuff that will impact older versions of Brioche!&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;(Minor breakage) TypeScript v6 and linting changes&lt;/h2&gt;
&lt;p&gt;This release jumps us from TypeScript v5.9.3-- &lt;a href=&quot;https://brioche.dev/blog/brioche-v0-1-7/#typescript-v593--eslint-upgrade&quot;&gt;introduced in the last release&lt;/a&gt;-- up to &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/&quot;&gt;TypeScript v6.0&lt;/a&gt;. I don&apos;t think most projects will see much impact one way or the other from this upgrade... but this is laying the groundwork to be able to use &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/#preparing-for-typescript-7.0&quot;&gt;TypeScript v7&lt;/a&gt; in the future!&lt;/p&gt;
&lt;p&gt;Additionally, Brioche now bundles a newer version of ESLint and typescript-eslint for linting, and enables some new lints by default. These linting changes &lt;strong&gt;could cause some breakages, especially in CI&lt;/strong&gt;-- e.g. if you&apos;re using either the &lt;code&gt;brioche check&lt;/code&gt; subcommand or the &lt;code&gt;--check&lt;/code&gt; flag. I think &lt;em&gt;most&lt;/em&gt; projects will get by without any changes required.&lt;/p&gt;
&lt;p&gt;The new lint rules we&apos;re enabling now are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/strict-void-return/&quot;&gt;&lt;code&gt;strict-void-return&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/no-useless-default-assignment/&quot;&gt;&lt;code&gt;no-useless-default-assignment&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/no-unnecessary-template-expression/&quot;&gt;&lt;code&gt;no-unnecessary-template-expression&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more context, check out &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;&apos;s PRs that introduced these changes: &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/465&quot;&gt;#465&lt;/a&gt; and &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/465&quot;&gt;#467&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Show source paths during builds&lt;/h2&gt;
&lt;p&gt;When jobs run building a package-- say, when a process recipe or a download is running-- you&apos;ll now see the source path in the TUI view, which gives you a better sense of which &lt;em&gt;step&lt;/em&gt; in your build is currently running.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./brioche-v0-1-8/source-locations.png&quot; alt=&quot;Terminal command: &amp;quot;brioche build ./packages/curl&amp;quot;. It shows a cache download running, annotated with the source path &amp;quot;openssl/project.bri:49:6&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Small heads up: some of the source paths that get shown aren&apos;t always the &lt;em&gt;most&lt;/em&gt; helpful. We thread through metadata to hide utility types wherever possible, but we&apos;ll probably need to make some updates to the &lt;code&gt;std&lt;/code&gt; package to make this more useful!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This improvement was introduced by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/466&quot;&gt;#466&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Linux sandbox improvements&lt;/h2&gt;
&lt;p&gt;This release includes a few more minor improvements to the Linux sandbox environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The sandbox user is now part of a group (via a new &lt;code&gt;/etc/groups&lt;/code&gt; file in the sandbox).&lt;/li&gt;
&lt;li&gt;Sandboxed programs now see a fixed hostname of &lt;code&gt;localhost&lt;/code&gt;, rather than the host system&apos;s hostname. To accommodate this, the sandbox now runs within an isolated UTS namespace.&lt;/li&gt;
&lt;li&gt;The sandbox now includes the files &lt;code&gt;/etc/services&lt;/code&gt; and &lt;code&gt;/etc/protocols&lt;/code&gt;. This helps with glibc compatibility (e.g. the functions &lt;code&gt;getservbyname&lt;/code&gt; and &lt;code&gt;getprotobyname&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These improvements were added in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/459&quot;&gt;#459&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Reader support for new cache archive tag&lt;/h2&gt;
&lt;p&gt;Since the &lt;a href=&quot;https://brioche.dev/blog/announcing-brioche-v0-1-5/#new-cache&quot;&gt;cache overhaul in Brioche v0.1.5&lt;/a&gt;, we&apos;ve used a custom archive format to store artifacts in the cache. This format has gone unchanged since it was first introduced... until now that is!&lt;/p&gt;
&lt;p&gt;Brioche v0.1.8 now supports reading archives with a new &lt;code&gt;R&lt;/code&gt; tag. This tag references another entry in the artifact by path, allowing for efficiently deduplicating complex directory trees.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; added this change in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/460&quot;&gt;#460&lt;/a&gt;, in order to unblock the (longstanding!) &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/2693&quot;&gt;&lt;code&gt;abseil_cpp&lt;/code&gt; PR&lt;/a&gt; in the &lt;code&gt;brioche-packages&lt;/code&gt; repo.&lt;/p&gt;
&lt;p&gt;Note that Brioche v0.1.8 doesn&apos;t support &lt;em&gt;writing&lt;/em&gt; this new archive tag yet! This is part of a 3-step plan:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Release support for reading the new archive tag in a stable release (you are here!)&lt;/li&gt;
&lt;li&gt;Add support for writing the new archive tag in a nightly release. This will then be used by &lt;code&gt;brioche-packages&lt;/code&gt;-- unblocking packages like &lt;code&gt;abseil_cpp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Release support for writing the new archive tag in a future stable release.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PSA:&lt;/strong&gt; Heads up that, once support for writing the new archive format lands, using the package cache for builds from &lt;code&gt;brioche-packages&lt;/code&gt; will require Brioche v0.1.8 or later! &lt;strong&gt;Users of Brioche v0.1.7 should upgrade to v0.1.8 soon!&lt;/strong&gt; Otherwise pulling new builds from the Brioche cache will start to fail!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;And... those are the highlights! There&apos;s some more goodies to be found &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.8&quot;&gt;in the release notes&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;I&apos;m glad to be getting into a better flow of &quot;smaller&quot; releases, with a few nice quality-of-life improvements and bugfixes. That said, there&apos;s some bigger stuff cooking too: I&apos;ve been tinkering with a larger-scale refactor, which should hopefully start to open more doors towards the larger ideas I have for Brioche! ...but, that may still be quite a ways off before that work is ready to see the light of day, so stay tuned for more news on that front over time!&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche v0.1.7: Simplified CLI</title><link>https://brioche.dev/blog/brioche-v0-1-7</link><guid isPermaLink="true">https://brioche.dev/blog/brioche-v0-1-7</guid><pubDate>Sun, 29 Mar 2026 22:25:48 GMT</pubDate><content:encoded>&lt;p&gt;It&apos;s finally spring, and it&apos;s finally time for the first Brioche release of 2026!&lt;/p&gt;
&lt;p&gt;When you&apos;re ready to jump in, run &lt;code&gt;brioche self-update&lt;/code&gt; to upgrade, or check the &lt;a href=&quot;/docs/installation&quot;&gt;installation docs&lt;/a&gt; if you&apos;re getting set up to the first time. If you want the nitty-gritty details, also feel free to check the &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.7&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Simplified CLI syntax&lt;/h2&gt;
&lt;p&gt;In Brioche v0.1.6 and prior, the CLI used the flags &lt;code&gt;-p&lt;/code&gt;, &lt;code&gt;-r&lt;/code&gt;, and &lt;code&gt;-e&lt;/code&gt; for specifying local projects, registry projects, and exports, respectively. With Brioche v0.1.7, we have a new, sleeker syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brioche check ./project # Previously: brioche check -p project
brioche build ./packages/llvm # Previously: brioche build -p package/llvm
brioche run curl -- https://example.com # Previously: brioche run -r curl -- https://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Building a local project is now specified by a relative path or absolute path, while remote registry projects are just specified with their name directly.&lt;/p&gt;
&lt;p&gt;Note that there&apos;s a trade-off here: relative paths always need to start with &lt;code&gt;./&lt;/code&gt; or &lt;code&gt;../&lt;/code&gt;. That is, &lt;code&gt;brioche build ./nodejs&lt;/code&gt; builds the &lt;em&gt;local&lt;/em&gt; &lt;code&gt;nodejs&lt;/code&gt; directory, where &lt;code&gt;brioche build nodejs&lt;/code&gt; builds the &lt;code&gt;nodejs&lt;/code&gt; project from the &lt;em&gt;registry&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;As for exports, these are specified with &lt;code&gt;^&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brioche build ./packages/llvm^test # Previously: brioche build -p packages/llvm -e test
brioche build ^frontend # Previously: brioche build -e frontend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The thing before the &lt;code&gt;^&lt;/code&gt; is the project (either a local path or registry project), and the thing after is the export name. Defaults to the current dir if no project is specified. You can even specify multiple exports separated by commas, e.g. &lt;code&gt;brioche build ^frontend,backend&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This change applies across the board to the CLI subcommands that take projects and/or exports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;brioche build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brioche run&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brioche install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brioche check&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brioche publish&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brioche live-update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brioche fmt&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;bonus&lt;/strong&gt;: &lt;code&gt;brioche fmt&lt;/code&gt; can also now take &lt;code&gt;.bri&lt;/code&gt; files by path, instead of reformatting a whole project!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new version a lot clearer in my opinion. It also means a shell command like &lt;code&gt;brioche build ./projects/*&lt;/code&gt; will work fine now, which is really convenient for complex CI pipelines!&lt;/p&gt;
&lt;p&gt;Big props to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; for implementing this across a series of PRs, and thanks all around for all the discussion about this change in &lt;a href=&quot;https://github.com/brioche-dev/brioche/discussions/320&quot;&gt;brioche-dev/brioche#320&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Oh, and &lt;strong&gt;the existing &lt;code&gt;-p&lt;/code&gt;, &lt;code&gt;-r&lt;/code&gt;, and &lt;code&gt;-e&lt;/code&gt; are considered deprecated&lt;/strong&gt;, but will continue to work for the forseeable future. They might go away in Brioche v0.2.0 or something, idk ¯\_(ツ)_/¯&lt;/p&gt;
&lt;h2&gt;Configurable split read/write cache&lt;/h2&gt;
&lt;p&gt;Do you ever find yourself in the situation where you use an S3-compatible object store for your content-addressed storage system, but you want to minimize reads to reduce your monthly bill, so you deploy &lt;a href=&quot;https://github.com/kylewlacy/server3&quot;&gt;your homegrown caching server for it&lt;/a&gt;, but you still want writes to go directly to S3?&lt;/p&gt;
&lt;p&gt;...no? Well, that&apos;s what happened to me! The CI pipeline for &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/&quot;&gt;&lt;code&gt;brioche-packages&lt;/code&gt;&lt;/a&gt; uses GitHub Actions with ephemeral runners, which means each change needs to pull a fair amount of stuff from the Brioche cache. Nearly every S3 provider bills for egress bandwidth or per API call or both, which means each CI run costs some money (though not much!) from the cache usage.&lt;/p&gt;
&lt;p&gt;That led me down a little detour to write a little caching server called &lt;a href=&quot;https://github.com/kylewlacy/server3&quot;&gt;server3&lt;/a&gt;-- which is now what powers &lt;code&gt;https://cache.brioche.dev&lt;/code&gt;. For a number of reasons, the cache is read-only: it can pull objects that already exist in S3 but can&apos;t write new objects. So ideally, we want the CI pipeline to &lt;em&gt;read from&lt;/em&gt; server3 but to &lt;em&gt;write to&lt;/em&gt; S3 directly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enter: the new &lt;code&gt;cache.write_url&lt;/code&gt; config option&lt;/strong&gt;! This can be used to specify a cache URL &lt;em&gt;just&lt;/em&gt; for writing. In the case of our CI pipeline, &lt;code&gt;cache.url&lt;/code&gt; is set to our &lt;code&gt;server3&lt;/code&gt; cache, while &lt;code&gt;cache.write_url&lt;/code&gt; is set to our upstream S3 provider.&lt;/p&gt;
&lt;p&gt;We&apos;ve seen pretty high cache-hit rates (~90% - 95%) for &lt;code&gt;brioche-packages&lt;/code&gt; builds, even with a pretty modest cache size (10 GB) and even across lots of package updates:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./brioche-v0-1-7/ci-cache-hits.png&quot; alt=&quot;Grafana dashboard with a pie chart labeled &amp;quot;Cache Hit Rate&amp;quot;: 92% cache hits (2.7 million total), 6% cache misses (180 thousand total), 1% not found (41 thousand total), 0% error (1 total), and 0% never (0 total). Next to it is a graph labeled &amp;quot;Cache hit Rate over Time&amp;quot; spanning the period from 3/22 to 3/29. It shows a high steady rate of cache hits (hovering around &amp;quot;10 c/s&amp;quot;), and infrequent, spikier cache misses (one peak around &amp;quot;-10 c/s&amp;quot; and another around &amp;quot;-5 c/s&amp;quot;)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Anyway, check out the &lt;a href=&quot;https://brioche.dev/docs/configuration/#cache-configuration&quot;&gt;&quot;Cache configuration&quot; docs&lt;/a&gt; for details, or see &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/422&quot;&gt;#422&lt;/a&gt; where this option was added.&lt;/p&gt;
&lt;h2&gt;Sandbox: Resolve &lt;code&gt;localhost&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;When building recipes in the &lt;a href=&quot;https://brioche.dev/docs/how-it-works/sandboxing/&quot;&gt;Linux sandbox&lt;/a&gt;, &lt;code&gt;localhost&lt;/code&gt; now resolves to the loopback IP addresses &lt;code&gt;127.0.0.1&lt;/code&gt; (IPv4) and &lt;code&gt;::1&lt;/code&gt; (IPv6), as it should. Yay!&lt;/p&gt;
&lt;p&gt;This was added by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/445&quot;&gt;#445&lt;/a&gt;, which came up in response to &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/3473&quot;&gt;an update for the &lt;code&gt;filebrowser&lt;/code&gt; package&lt;/a&gt;. For the update, File Browser switched from Vite 7 to Vite 8, which seems to do a DNS lookup for &lt;code&gt;localhost&lt;/code&gt; during the build. This seems totally reasonable to do during a build, even when networking is disabled, so it works now.&lt;/p&gt;
&lt;p&gt;...honestly, I hadn&apos;t though about &lt;code&gt;localhost&lt;/code&gt; &lt;em&gt;not&lt;/em&gt; resolving in the sandbox, and I&apos;m more surprised we&apos;ve gone this long without noticing issues before!&lt;/p&gt;
&lt;h2&gt;Experimental: Skipping cached artifacts&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; added a nifty debugging tool in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/401&quot;&gt;#401&lt;/a&gt;: &lt;code&gt;$BRIOCHE_SKIP_CACHE_ARTIFACTS&lt;/code&gt;. This env var is set to a comma-separated list of artifact hashes, and each is skipped from the upstream cache-- allowing you to build an artifact locally instead. This allows for investigating potential build issues where the cache is &quot;poisoned&quot; with bad artifacts (e.g. due to a bug in Brioche, memory corruption/bit flips, or any other reason). Or maybe you just want to benchmark how long it takes to build LLVM yourself.&lt;/p&gt;
&lt;p&gt;This addresses a long-standing need in &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/69&quot;&gt;#69&lt;/a&gt; (nice), although with a pretty rough interface. Longer term, I still want to see something that&apos;s more user-accessible that ideally doesn&apos;t require working out which specific hash(es) to ignore. But, the need for this came up, and perfect is the enemy of good, as they say. I&apos;m &lt;em&gt;all for&lt;/em&gt; adding weird/fun debugging tools as necessary, and so I thought it made sense to get this in as-is to buy us time for a &quot;proper&quot; solution for &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/69&quot;&gt;#69&lt;/a&gt; (nice).&lt;/p&gt;
&lt;h2&gt;TypeScript v5.9.3 + ESLint upgrade&lt;/h2&gt;
&lt;p&gt;This release jumps us up from TypeScript v5.3.3-- introduced in the initial Brioche release-- all the way to v5.9.3! We actually haven&apos;t had any type-checking regressions or breakages from this (that we&apos;ve seen anyway). So overall, this upgrade was pretty pedestrian (by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/388&quot;&gt;#388&lt;/a&gt;), which is good!&lt;/p&gt;
&lt;p&gt;More importantly, this gets us closer to &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/&quot;&gt;TypeScript v6.0&lt;/a&gt;, which in turn will be a stepping stone for us to use TypeScript&apos;s Go rewrite in v7! I&apos;ve been keeping a watchful eye on TypeScript v7&apos;s progress, although at the time of writing, it seems like the compiler API is still not far enough along for us to integrate with: we&apos;re still waiting with bated breath for news on that front.&lt;/p&gt;
&lt;p&gt;As for TypeScript v6, it was just released last week, and I didn&apos;t feel like it was worth holding up the Brioche release to get the next upgrade in. But anticipate TypeScript v6 in Brioche in the near future!&lt;/p&gt;
&lt;p&gt;...oh, and we had a bunch of other package upgrades too, including ESLint. We&apos;re still using a pretty small list of lint rules, but keeping up on ESLint updates keeps the door open for newer/better/improved Brioche lints over time.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Anyway, that&apos;s the release! This is our second release with &lt;a href=&quot;https://brioche.dev/blog/brioche-v0-1-6/#release-process-changes&quot;&gt;our new release process&lt;/a&gt;... which if you think about it, really makes this the &lt;em&gt;first&lt;/em&gt; release with the new release process. (Okay, but really: this is the first release where updates utilize the new release process!)&lt;/p&gt;
&lt;p&gt;I&apos;ve also been &lt;a href=&quot;https://brioche.dev/blog/&quot;&gt;pretty quiet on the blog lately&lt;/a&gt;. Partially that&apos;s because 2026 has been... weird for me so far, and I&apos;ve had other Life Things come up that have taken away my time from Brioche in general. Partially it&apos;s because, for 2025, I made it a goal of mine to get out a Project Update post every month before the end of the month-- which I did and I&apos;m glad about! But on reflection, I think I&apos;d enjoy doing less frequent, more focused blog posts in general. I&apos;m still &lt;em&gt;really&lt;/em&gt; proud of the &lt;a href=&quot;https://brioche.dev/blog/portable-dynamically-linked-packages-on-linux/&quot;&gt;&quot;Portable, dynamically linked packages on Linux&quot;&lt;/a&gt; article, and I&apos;ve got a small queue of other articles to work on writing soon(-ish).&lt;/p&gt;
&lt;p&gt;I think there will be more Project Updates, but probably less often and &quot;when it makes sense&quot;, instead of on a specific schedule.&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - December 2025</title><link>https://brioche.dev/blog/project-update-2025-12</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-12</guid><pubDate>Wed, 31 Dec 2025 10:45:08 GMT</pubDate><content:encoded>&lt;p&gt;import PackageList from &quot;./project-update-2025-12/PackageList.astro&quot;;&lt;/p&gt;
&lt;p&gt;It&apos;s the final project update of the year! With the holidays and... life stuff, this month was a little slower for me for Brioche work. But there&apos;s still a lot of exciting stuff to share, and we just crossed another major package milestone!!! 🎉&lt;/p&gt;
&lt;h2&gt;Highlights from the year&lt;/h2&gt;
&lt;p&gt;With the year coming to a close, I wanted to start with a quick look back at some of the major milestones we reached this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Packages&lt;/em&gt;: from &lt;strong&gt;50 packages&lt;/strong&gt; at the start of January to &lt;a href=&quot;#new-packages&quot;&gt;&lt;strong&gt;over 500 packages 🎉&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Brioche&lt;/em&gt;: &lt;strong&gt;3 new releases&lt;/strong&gt; this year:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/announcing-brioche-v0-1-4&quot;&gt;Brioche v0.1.4&lt;/a&gt; (January): prettier output, packed Brioche builds&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/announcing-brioche-v0-1-5&quot;&gt;Brioche v0.1.5&lt;/a&gt; (April): new cache, debug shell for failed builds&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/brioche-v0-1-6&quot;&gt;Brioche v0.1.6&lt;/a&gt; (November): aarch64 support, new release process&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Made possible with the help of &lt;strong&gt;10 contributors&lt;/strong&gt; in the past year!
&lt;ul&gt;
&lt;li&gt;Members of the &lt;code&gt;brioche-dev&lt;/code&gt; org: &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;, and &lt;a href=&quot;https://github.com/kylewlacy&quot;&gt;&lt;strong&gt;@kylewlacy&lt;/strong&gt;&lt;/a&gt; (me!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chad-russell&quot;&gt;&lt;strong&gt;@chad-russell&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/jokeyrhyme&quot;&gt;&lt;strong&gt;@jokeyrhyme&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/paricbat&quot;&gt;&lt;strong&gt;@paricbat&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/kaathewisegit&quot;&gt;&lt;strong&gt;@kaathewisegit&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/running-grass&quot;&gt;&lt;strong&gt;@running-grass&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/nz366&quot;&gt;&lt;strong&gt;@nz366&lt;/strong&gt;&lt;/a&gt;, and &lt;a href=&quot;https://github.com/easrng&quot;&gt;&lt;strong&gt;@easrng&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;...plus everyone who participated with issues, discussions, and ideas (and any other contributors I missed!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;TypeScript 5.9.3 upgrade&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/388&quot;&gt;#388&lt;/a&gt; to upgrade the TypeScript version embedded in Brioche from v5.3.3 to v5.9.3! We didn&apos;t spot any breakages across the &lt;code&gt;brioche-packages&lt;/code&gt; repo during this upgrade, so this should be a pretty safe update that should give us a few new type-level tools and checks for free.&lt;/p&gt;
&lt;p&gt;This feels like the right time to upgrade, since this is the last TypeScript version before v6.0, which is then the final release before the native TypeScript port in v7.0! There was a blog post earlier this month about &lt;a href=&quot;https://devblogs.microsoft.com/typescript/progress-on-typescript-7-december-2025/&quot;&gt;TypeScript&apos;s progress towards the native port in v7.0&lt;/a&gt;. I&apos;m hoping that we&apos;ll be able to integrate TypeScript 7 into Brioche not long after it&apos;s ready to go, so we can take advantage of the major speed boost in type-checking!&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;brioche fmt&lt;/code&gt; improvements&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;brioche fmt&lt;/code&gt; got some nice quality-of-life improvements from &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/386&quot;&gt;#386&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-p&lt;/code&gt; flag is no longer necessary (since you&apos;d only ever want to format a local project, never one remotely!), and additionally you can now format individual &lt;code&gt;.bri&lt;/code&gt; files instead of a full project directory!&lt;/p&gt;
&lt;p&gt;These commands are now all (roughly) equivalent:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brioche fmt packages/std
brioche fmt -p packages/std
brioche fmt packages/std/**/*.bri
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;More major groundwork packages&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; has continued a streak of gettings lots of new exciting packages done, and that includes a ton more work towards Linux GUI applications! I&apos;ll share his summary of the changes from just the past week:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I did a lot of things during the last week, I was mainly focused on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;packaging the core libraries to later build bigger ones such as Mesa, FFMPEG, Wayland, etc. We do need a lot of core things right now, but I&apos;m moving in the right direction&lt;/li&gt;
&lt;li&gt;adding more common CLI tools to reach a broader audience&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&apos;s a &lt;em&gt;lot&lt;/em&gt; of X11/Wayland packages in the modern Linux desktop stack, but we&apos;re starting to get a lot of packages from that ecosystem wired up, so it&apos;s really exciting progress!&lt;/p&gt;
&lt;p&gt;(and personally, ffmpeg is one I&apos;m really excited about-- although that one is kind of its own little black hole of package management challenges!)&lt;/p&gt;
&lt;h3&gt;Sad personal news&lt;/h3&gt;
&lt;p&gt;Midway through the month, we put our 15-year-old cat to sleep. She was amazing and lived a long, loving, happy life, but it was still sudden and it&apos;s been real hard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./project-update-2025-12/abby.jpg&quot; alt=&quot;Adorable calico cat laying on the floor, basking in the sunlight from the window. She&apos;s laying on her side with her paws out and looking at you relaxedly, waiting for belly rubs.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So overall, this month has been pretty slow-going for me.&lt;/p&gt;
&lt;p&gt;If you&apos;ve got a cat or other fuzzy creature, give them cuddles and a big pet for me.&lt;/p&gt;
&lt;h3&gt;Continued infrastructure work&lt;/h3&gt;
&lt;p&gt;Well, with the time I did spend on Brioche this month, I mostly continued on with the &lt;a href=&quot;/blog/project-update-2025-11/#infrastructure-rework&quot;&gt;infrastructure work I discussed last month&lt;/a&gt;. I made some good steps forward, and the foundation is pretty sturdy now! ...although a lot of it is &quot;in the weeds&quot; Kubernetes stuff (Longhorn for storage, Grafana for monitoring, etc.), so nothing really exciting to share yet.&lt;/p&gt;
&lt;h3&gt;Minor caching tweaks&lt;/h3&gt;
&lt;p&gt;I opened and merged &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/379&quot;&gt;#379&lt;/a&gt;, which added some very minor tweaks to the cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retry &lt;code&gt;PUT&lt;/code&gt; requests&lt;/li&gt;
&lt;li&gt;Allow customizing cache timeouts through config / env vars&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This change is pretty unassuming, but came up after a hair-pulling debugging session of failures in the &lt;code&gt;brioche-packages&lt;/code&gt; repo, where builds were failing to upload to the cache sporadically. I think the root cause was related to some weird DNS quirks from some of my recent infrastructure work. But after getting this change in, then bumping up one of the timeouts in the &lt;code&gt;brioche-packages&lt;/code&gt; workflow in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/2073&quot;&gt;&lt;code&gt;brioche-dev/brioche-packages#2073&lt;/code&gt;&lt;/a&gt;, things have been running smoothly.&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;159&lt;/strong&gt; new packages. During this month, we blew past another major milestone:&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;font-bold text-xl&quot;&amp;gt;🎉 Brioche now has over 500 packages! 🎉&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;(At the time of writing, we&apos;re sitting at 514, with about 2 dozen more in the build queue!)&lt;/p&gt;
&lt;p&gt;As is tradition, here are all the new packages this month:&lt;/p&gt;
&lt;p&gt;&amp;lt;PackageList
packages={[
&quot;3cpio&quot;,
&quot;6tunnel&quot;,
&quot;aardvark_dns&quot;,
&quot;acl&quot;,
&quot;acme_redirect&quot;,
&quot;act&quot;,
&quot;aerleon&quot;,
&quot;aften&quot;,
&quot;age&quot;,
&quot;age_plugin_yubikey&quot;,
&quot;argocd&quot;,
&quot;audit&quot;,
&quot;autoprefixer&quot;,
&quot;bacon_ls&quot;,
&quot;berkeley_db&quot;,
&quot;bkmr&quot;,
&quot;bosh_cli&quot;,
&quot;c_ares&quot;,
&quot;cairo&quot;,
&quot;cargo_shear&quot;,
&quot;ccusage&quot;,
&quot;cdebug&quot;,
&quot;cf_terraforming&quot;,
&quot;cglm&quot;,
&quot;cilium_cli&quot;,
&quot;cliproxyapi&quot;,
&quot;clive&quot;,
&quot;clorinde&quot;,
&quot;cloud_nuke&quot;,
&quot;comrak&quot;,
&quot;copilot_language_server&quot;,
&quot;coredns&quot;,
&quot;cpio&quot;,
&quot;cppcheck&quot;,
&quot;cubejs_cli&quot;,
&quot;docker_compose&quot;,
&quot;dolt&quot;,
&quot;dysk&quot;,
&quot;esbuild&quot;,
&quot;fabio&quot;,
&quot;fabric_ai&quot;,
&quot;flac&quot;,
&quot;fmt&quot;,
&quot;forgejo_runner&quot;,
&quot;freeimage&quot;,
&quot;fresh_editor&quot;,
&quot;gflags&quot;,
&quot;gfold&quot;,
&quot;giflib&quot;,
&quot;gitlab_runner&quot;,
&quot;gleam&quot;,
&quot;glib&quot;,
&quot;glm&quot;,
&quot;go_security_tracker&quot;,
&quot;gost&quot;,
&quot;graphite2&quot;,
&quot;graphql_client_cli&quot;,
&quot;hwloc&quot;,
&quot;ipsw&quot;,
&quot;jarl&quot;,
&quot;jbig2dec&quot;,
&quot;jd&quot;,
&quot;lazygit&quot;,
&quot;lefthook&quot;,
&quot;lf&quot;,
&quot;libaec&quot;,
&quot;libbsd&quot;,
&quot;libgcrypt&quot;,
&quot;libgpg_error&quot;,
&quot;libiconv&quot;,
&quot;libidn&quot;,
&quot;libidn2&quot;,
&quot;libmd&quot;,
&quot;libogg&quot;,
&quot;libpipeline&quot;,
&quot;libsamplerate&quot;,
&quot;libselinux&quot;,
&quot;libsemanage&quot;,
&quot;libsepol&quot;,
&quot;libtasn1&quot;,
&quot;libudev_zero&quot;,
&quot;liburing&quot;,
&quot;libvorbis&quot;,
&quot;libwebp&quot;,
&quot;lz4&quot;,
&quot;mailpit&quot;,
&quot;mcp_server_kubernetes&quot;,
&quot;meilisearch&quot;,
&quot;melange&quot;,
&quot;mesheryctl&quot;,
&quot;microsoft_gsl&quot;,
&quot;monocle&quot;,
&quot;mq&quot;,
&quot;munge&quot;,
&quot;nghttp2&quot;,
&quot;nghttp3&quot;,
&quot;npq&quot;,
&quot;numactl&quot;,
&quot;oh_my_posh&quot;,
&quot;open_policy_agent&quot;,
&quot;openjpeg&quot;,
&quot;orc&quot;,
&quot;oterm&quot;,
&quot;p11_kit&quot;,
&quot;pack&quot;,
&quot;parlay&quot;,
&quot;parquet_tools&quot;,
&quot;pcsc_lite&quot;,
&quot;pinact&quot;,
&quot;poetry&quot;,
&quot;popt&quot;,
&quot;prek&quot;,
&quot;prettier&quot;,
&quot;ragel&quot;,
&quot;range_v3&quot;,
&quot;rbspy&quot;,
&quot;resterm&quot;,
&quot;restish&quot;,
&quot;rnr&quot;,
&quot;robotframework&quot;,
&quot;rosa&quot;,
&quot;rqlite&quot;,
&quot;rust_bindgen&quot;,
&quot;rustic&quot;,
&quot;rv&quot;,
&quot;sass&quot;,
&quot;shadowsocks_rust&quot;,
&quot;simdjson&quot;,
&quot;soxr&quot;,
&quot;spirv_headers&quot;,
&quot;swc&quot;,
&quot;systemfd&quot;,
&quot;tinyxml2&quot;,
&quot;tllist&quot;,
&quot;tombi&quot;,
&quot;topgrade&quot;,
&quot;treemd&quot;,
&quot;tuios&quot;,
&quot;tzdata&quot;,
&quot;utf8proc&quot;,
&quot;valkey&quot;,
&quot;vespa_cli&quot;,
&quot;vgt&quot;,
&quot;vite&quot;,
&quot;viu&quot;,
&quot;watchexec&quot;,
&quot;wayland&quot;,
&quot;wayland_protocols&quot;,
&quot;weaviate&quot;,
&quot;xcb_util_cursor&quot;,
&quot;xcb_util_keysyms&quot;,
&quot;xcb_util_renderutil&quot;,
&quot;xcb_util_wm&quot;,
&quot;xk6&quot;,
&quot;xvidcore&quot;,
&quot;z3&quot;,
&quot;zerofs&quot;,
&quot;zimg&quot;,
&quot;zuban&quot;,
]}
/&amp;gt;&lt;/p&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;build: update dependencies in runtime NPM project (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/375&quot;&gt;#375&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Tweak cache timeouts and retries (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/379&quot;&gt;#379&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update package-lock.json (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/377&quot;&gt;#377&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;build: update transient dependencies to latest versions (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/378&quot;&gt;#378&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;chore: resolve new warnings from Clippy 1.92 (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/387&quot;&gt;#387&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;feat: update typescript to its latest version (5.3.3) (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/388&quot;&gt;#388&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update Dependabot config to ignore major versions of Bincode (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/391&quot;&gt;#391&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;chore: revamp the command format, and add the ability to format files (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/386&quot;&gt;#386&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix typo in dependabot.yml (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/393&quot;&gt;#393&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - November 2025</title><link>https://brioche.dev/blog/project-update-2025-11</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-11</guid><pubDate>Sun, 30 Nov 2025 20:55:20 GMT</pubDate><content:encoded>&lt;p&gt;This month, there&apos;s been a new release, lots of infrastructure work, and a bunch more packages&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Brioche v0.1.6 released&lt;/h3&gt;
&lt;p&gt;Shortly after the last status update, we released &lt;a href=&quot;/blog/brioche-v0-1-6&quot;&gt;Brioche v0.1.6&lt;/a&gt;, so if you missed the news go check it out! The headline feature is official support for aarch64 Linux as a platform, but there are lots of other goodies packed in the release too.&lt;/p&gt;
&lt;p&gt;Internally, this was the first time we got to use &lt;a href=&quot;/blog/brioche-v0-1-6/#release-process-changes&quot;&gt;our new release process&lt;/a&gt; to cut the release (which I also &lt;a href=&quot;/blog/project-update-2025-10/#installer--release-work&quot;&gt;talked about in last month&apos;s Project Update&lt;/a&gt;). Mostly, this was exciting because it didn&apos;t blow up!&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;setup-brioche&lt;/code&gt; action overhaul&lt;/h3&gt;
&lt;p&gt;The new release came from our new release process. Our new release process included a new installer script. The new installer script also enabled us to massively simplify our &lt;a href=&quot;https://github.com/brioche-dev/setup-brioche&quot;&gt;&lt;code&gt;setup-brioche&lt;/code&gt;&lt;/a&gt; GitHub Action.&lt;/p&gt;
&lt;p&gt;The initial version of the &lt;code&gt;setup-brioche&lt;/code&gt; action bundled its own install script, which was nearly identical to the (old) install script. But, it started to grow out as we added features. That also meant any changes to the main install script needed to be ported over to the action too.&lt;/p&gt;
&lt;p&gt;Now, the new install script (&lt;a href=&quot;https://github.com/brioche-dev/brioche-installer&quot;&gt;&lt;code&gt;brioche-installer&lt;/code&gt;&lt;/a&gt;) includes all the custom functionality that was originally just added to the &lt;code&gt;setup-brioche&lt;/code&gt; script (opt-in, of course). So now, &lt;code&gt;setup-brioche&lt;/code&gt; can just pull the official installer and run it!&lt;/p&gt;
&lt;p&gt;But, from a supply-chain security perspective, fetching and executing a live-updating shell script is... uh... somewhat risky! To help matters, the installer script itself is code-signed, and we explicitly check the signature before running the installer. I feel this helps us maintain a strong security posture for the action, along with &lt;em&gt;massively&lt;/em&gt; simplifying the maintenance.&lt;/p&gt;
&lt;h3&gt;New aarch64 runner&lt;/h3&gt;
&lt;p&gt;For &lt;code&gt;brioche-package&lt;/code&gt; builds, we use our own self-hosted runners. Specifically, we have a Minisforum mini PC as an x86-64 runner, and an M1 Mac mini as an aarch64 runner (running &lt;a href=&quot;https://asahilinux.org/&quot;&gt;Asahi Linux&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For some time now, the aarch64 builds have been a bottleneck in our package builds (not that the Mac mini is a slouch! But it&apos;s not quite at the core count we&apos;d want for building packages). To help it out, a new Nvidia DGX Spark joined the fray!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./project-update-2025-11/dgx-spark.jpg&quot; alt=&quot;A gaudy, gold mini PC sitting on top of a box labeled &amp;quot;NVIDIA DGX Spark&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I might be one of the few people who bought this thing &lt;em&gt;not&lt;/em&gt; for AI stuff. I&apos;ve been watching this space for a while, and I believe it&apos;s the first ARM-based mini PC &lt;em&gt;not&lt;/em&gt; made by Apple that reaches the performance level of Apple&apos;s M1.&lt;/p&gt;
&lt;p&gt;...and for better or for worse, it was the best option I had for another aarch64 build machine. Ampere&apos;s stuff is interesting, but more targetted for enterprises I think and not really consumer-facing; Qualcomm has &lt;em&gt;talked about&lt;/em&gt; ARM PCs for quite a while without really shipping anything I could get my hands on today; Minisforum shipped the &lt;a href=&quot;https://www.minisforum.com/products/ms-r1&quot;&gt;MS-R1&lt;/a&gt; recently but performance isn&apos;t stellar from what I&apos;ve read; Apple&apos;s making some really solid stuff, but Asahi only supports M1/M2, so using Mac hardware would either mean buying older hardware for Asahi support or virtualizing Linux on top of macOS (more painful to manage).&lt;/p&gt;
&lt;p&gt;Together, the DGX Spark and the Mac mini are keeping ARM builds roughly on pace with x86-64. That&apos;s good because that&apos;s cleared a bottleneck in our build pipelines!&lt;/p&gt;
&lt;p&gt;(I was kind of hoping the DGX Spark alone could keep up with the x86-64 runner, but that hasn&apos;t really played out. That said, I&apos;ve seen some slowness on both the DGX Spark &lt;em&gt;and&lt;/em&gt; the Mac mini that makes me want to dig in more on general performance of aarch64 for Brioche + our CI pipeline. I&apos;m not ready to make any claims about the DGX Spark&apos;s performance, to be honest!)&lt;/p&gt;
&lt;h3&gt;Python packaging fixes&lt;/h3&gt;
&lt;p&gt;For a long time, our &lt;code&gt;meson&lt;/code&gt; has had an issue where it would try to use the wrong Python interpreter (issue &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/issues/838&quot;&gt;#838&lt;/a&gt;). Basically, the &lt;code&gt;bin/meson&lt;/code&gt; script ended up with a shebang with an invalid path (well, a path that was only valid within a single instance of the sandbox).&lt;/p&gt;
&lt;p&gt;Well, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1669&quot;&gt;#1669&lt;/a&gt;, which finally fixed this for good by using a proper shebang. Now, &lt;code&gt;bin/meson&lt;/code&gt; uses the shebang line &lt;code&gt;#!/usr/bin/env sh&lt;/code&gt; with a small &lt;em&gt;polyglot script&lt;/em&gt; to execute the actual Python interpreter. This fix is also reusable and applies to other Python-based packages too!&lt;/p&gt;
&lt;h3&gt;Lots more foundational X11 packages&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; has been busy adding a bunch of new packages related to X11/X.Org. We don&apos;t have any GUI-based packages in Brioche yet, but all of these dependencies are prerequisites on the path to getting the first one added!&lt;/p&gt;
&lt;h3&gt;Infrastructure rework&lt;/h3&gt;
&lt;p&gt;Our GitHub Actions runners are managed with GitHub&apos;s (in)famous &lt;a href=&quot;https://github.com/actions/actions-runner-controller&quot;&gt;Actions Runner Controller&lt;/a&gt; for Kubernetes. Previously, I set things up the lazy way by creating a separate Kubernetes &quot;cluster&quot; for each runner-- not really ideal!&lt;/p&gt;
&lt;p&gt;With the new DGX Spark runner, I used this as a chance to overhaul the Kubernetes setup used for Brioche stuff. Now, each of our 3 runners are part of a single cluster, which makes it easy to view and manage all the runners together!&lt;/p&gt;
&lt;p&gt;Actually, I&apos;m hoping this is a 2-for-1 deal. Today, a lot of Brioche&apos;s infrastructure is hosted by Cloudflare (plus some parts using &lt;a href=&quot;https://fly.io/&quot;&gt;Fly.io&lt;/a&gt; and &lt;a href=&quot;https://neon.com/&quot;&gt;Neon&lt;/a&gt;). I&apos;ve honestly been unhappy with using Cloudflare for a long time[^cloudflare], and have long had the itch to move. Recently, I was inspired by &lt;a href=&quot;https://grebedoc.dev/&quot;&gt;Grebedoc&lt;/a&gt; and the modest infrastructure that powers it. So this month, I&apos;ve been trying to get all the pieces in place for a &quot;production-ready&quot; Kubernetes cluster for self-hosting more Brioche infrastructure.&lt;/p&gt;
&lt;p&gt;It&apos;s been... pretty painful getting everything working! But my hope is that this will be a long-term investment to keep Brioche&apos;s infrastructure small, sustainable, reliable, and fast! I&apos;m hoping to write a lot more words about what I&apos;ve been cooking once I&apos;ve got more to share.&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;48&lt;/strong&gt; new packages.&lt;/p&gt;
&lt;p&gt;New packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aicommit2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_leptos&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chezmoi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;corrosion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;datafusion_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delta&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dumbpipe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font_util&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fontconfig&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fonttools&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git_spice&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;harsh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm_docs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helmfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helmify&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;httm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;impala&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;leetcode_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libfontenc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libimagequant&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libpciaccess&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxcvt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxft&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxinerama&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxkbfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxshmfence&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxxf86dga&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxxf86vm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lzlib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markdown_oxide&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mergiraf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nexttrace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;numcpp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ov&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parqeye&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pixman&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rulesync&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rustnet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stylelint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;topiary&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vfox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vtcode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xauth&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xcb_util&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xcb_util_errors&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xcb_util_image&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/363&quot;&gt;#363&lt;/a&gt;: Update Cargo configuration&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/364&quot;&gt;#364&lt;/a&gt;: Work around race condition between &quot;didOpen&quot; and &quot;diagnostic&quot; LSP messages&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/366&quot;&gt;#366&lt;/a&gt;: Update LSP to load documents atomically&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/367&quot;&gt;#367&lt;/a&gt;: ci: remove old hack, now Brioche 0.1.6 is out&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[^cloudflare]: Even from day one, I wasn&apos;t super enthusiastic about using Cloudflare. Their &lt;a href=&quot;https://blog.cloudflare.com/18-november-2025-outage/&quot;&gt;outage this month&lt;/a&gt; was timely-- although I&apos;m not really concerned about their uptime, but I don&apos;t like how centralized they&apos;ve helped make the Web. More concerning to me is their policies and who they openly support. They &lt;a href=&quot;https://blog.cloudflare.com/kiwifarms-blocked/&quot;&gt;did stop protecting Kiwi Farms-- eventually&lt;/a&gt; (good). But there&apos;s also a notorious forum centered on self-harm-- &lt;a href=&quot;https://www.youtube.com/watch?v=C3y6SsGAWks&quot;&gt;there&apos;s a great video esssay about it by Tantacrul&lt;/a&gt;-- which Cloudflare still protects &lt;em&gt;today&lt;/em&gt;. They also &lt;a href=&quot;https://blog.cloudflare.com/supporting-the-future-of-the-open-web/&quot;&gt;proudly sponsor&lt;/a&gt; the projects Omarchy (the Linux distro made by DHH, &lt;a href=&quot;https://jakelazaroff.com/words/dhh-is-way-worse-than-i-thought/&quot;&gt;who is a white supremacist&lt;/a&gt;) and Ladybird (the browser started by Andreas Kling, &lt;a href=&quot;https://github.com/SerenityOS/serenity/pull/6814&quot;&gt;who feels that gender-neutral langauge is &quot;political&quot; and, therefore, not welcome in his projects&lt;/a&gt;). Life&apos;s too short, and I&apos;d rather support providers I like. Cloudflare does not spark joy.&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche v0.1.6: Now for ARM64!</title><link>https://brioche.dev/blog/brioche-v0-1-6</link><guid isPermaLink="true">https://brioche.dev/blog/brioche-v0-1-6</guid><pubDate>Sun, 02 Nov 2025 22:29:45 GMT</pubDate><content:encoded>&lt;p&gt;Well, it&apos;s been a while since the release of &lt;a href=&quot;/blog/announcing-brioche-v0-1-5&quot;&gt;Brioche v0.1.5&lt;/a&gt;. We&apos;ve got some exciting new features in this release, plus Brioche finally supports &lt;strong&gt;aarch64 Linux&lt;/strong&gt; (a.k.a ARM64 Linux) as a platform!&lt;/p&gt;
&lt;p&gt;Whether you&apos;re new to Brioche or want to try out the latest improvements, check out the &lt;a href=&quot;/docs/installation&quot;&gt;installation docs&lt;/a&gt; for instructions on installing the latest release! Oh, and if you want a detailed breakdown of all the changes from this release, check out the &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.6&quot;&gt;release notes&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;(and small heads up: there were some &lt;a href=&quot;#release-process-changes&quot;&gt;major changes to the release process&lt;/a&gt;, so automatic updates with &lt;code&gt;brioche self-update&lt;/code&gt; aren&apos;t available for existing installations for this release! sorry!!)&lt;/p&gt;
&lt;h2&gt;aarch64 support&lt;/h2&gt;
&lt;p&gt;If you&apos;re on an aarch64 machine, you can now install Brioche! It&apos;d be hard to even tell that anything&apos;s different from an x86-64 machine.&lt;/p&gt;
&lt;p&gt;Behind the scenes, it took a lot of work to reach this point. We needed to pull in aarch64 versions of our sandbox rootfs components, add a way for build scripts to distinguish the current platform, update the toolchain to for native aarch64 compilation, rebuild and fix all of our existing packages, and set up a CI runner for package builds. We&apos;ve had all this up and running in nightly &lt;a href=&quot;/blog/project-update-2025-06#aarch64-linux-support&quot;&gt;since June&lt;/a&gt;, so &lt;strong&gt;all existing packages in the Brioche Packages repo are supported on aarch64 now, and provided in the cache!&lt;/strong&gt; &amp;lt;sup&amp;gt;(...with a few exceptions when an upstream package doesn&apos;t support aarch64!!)&amp;lt;/sup&amp;gt;&lt;/p&gt;
&lt;p&gt;This is another step on our goal towards great cross-platform and cross-compilation support in Brioche. With &lt;em&gt;native compilation&lt;/em&gt; for aarch64, this is a stepping stone towards &lt;em&gt;cross-compilation&lt;/em&gt;. Also, going from &lt;em&gt;one&lt;/em&gt; to &lt;em&gt;two&lt;/em&gt; platforms is a stepping stone to &lt;em&gt;lots&lt;/em&gt; of platforms. (Check the GitHub Discussion &lt;a href=&quot;https://github.com/brioche-dev/brioche/discussions/302&quot;&gt;on cross compilation&lt;/a&gt; too, if you&apos;re interested!)&lt;/p&gt;
&lt;h2&gt;Live updates&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;/packages&quot;&gt;Brioche Packages&lt;/a&gt; repo is growing steadily-- and we &lt;a href=&quot;/blog/project-update-2025-10&quot;&gt;just crossed 300 packages&lt;/a&gt;! With only a small number of maintainers, we need to be thoughtful in how we stay on top of continual package updates over time.&lt;/p&gt;
&lt;p&gt;That&apos;s where live updates come in: a tool for automated package updates. Basically, each package defines its &quot;live update&quot; script. Then, we have a CI job that runs weekly, calls each package&apos;s live update script, then creates a PR automatically for each out-of-date package. From there, the PRs go through review. We&apos;re able to merge most update PRs as-is, and the rest act as a starting point for manual changes.&lt;/p&gt;
&lt;p&gt;Let&apos;s go through a little example to see live updates in action. Here&apos;s a Brioche project for building &lt;a href=&quot;https://github.com/eza-community/eza&quot;&gt;eza&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as std from &quot;std&quot;;
import { cargoBuild } from &quot;rust&quot;;

export const project = {
  name: &quot;eza&quot;,
  version: &quot;0.23.3&quot;,
  repository: &quot;https://github.com/eza-community/eza.git&quot;,
};

const source = Brioche.gitCheckout({
  repository: project.repository,
  ref: `v${project.version}`,
});

export default function eza(): std.Recipe&amp;lt;std.Directory&amp;gt; {
  return cargoBuild({
    source,
    runnable: &quot;bin/eza&quot;,
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...oh, but our package is already out-of-date! &lt;a href=&quot;https://github.com/eza-community/eza/releases/tag/v0.23.4&quot;&gt;eza v0.23.3 was released at the start of October&lt;/a&gt;. eza seems to have new versions published on their GitHub Releases page, so we&apos;ll use the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/4cdeef2a102cda612880090619e60407512e9c1d/packages/std/extra/live_update/from_github_releases.bri&quot;&gt;&lt;code&gt;std.liveUpdateFromGithubReleases&lt;/code&gt;&lt;/a&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ...

export function liveUpdate(): std.Recipe&amp;lt;std.Directory&amp;gt; {
  return std.liveUpdateFromGithubReleases({ project });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if we run &lt;code&gt;brioche live-update&lt;/code&gt;, we&apos;ll see that the version is automatically updated for us!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; export const project = {
   name: &quot;eza&quot;,
-  version: &quot;0.23.3&quot;,
+  version: &quot;0.23.4&quot;,
   repository: &quot;https://github.com/eza-community/eza.git&quot;,
 };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not just that, but our lockfile &lt;code&gt;brioche.lock&lt;/code&gt; was also updated, so it now points to the new commit for the &lt;code&gt;v0.23.4&lt;/code&gt; tag!&lt;/p&gt;
&lt;p&gt;Under the hood, each piece is pretty simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;brioche live-update&lt;/code&gt; builds and runs the &lt;code&gt;liveUpdate&lt;/code&gt; export from our project-- which in turn just uses &lt;code&gt;std.liveUpdateFromGithubReleases&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;std.liveUpdateFromGithubReleases&lt;/code&gt; uses &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/4cdeef2a102cda612880090619e60407512e9c1d/packages/std/extra/live_update/scripts/live_update_from_github_releases.nu&quot;&gt;a small Nushell script&lt;/a&gt; to call the GitHub Releases API. It takes our starting &lt;code&gt;project&lt;/code&gt; export, updates the version based on the API response, and prints the new value as JSON to stdout.&lt;/li&gt;
&lt;li&gt;Brioche parses the JSON, then updates our &lt;code&gt;project.bri&lt;/code&gt;, substituting the previous &lt;code&gt;export const project&lt;/code&gt; with the JSON value.&lt;/li&gt;
&lt;li&gt;Brioche updates the lockfile, if needed. This works because &lt;a href=&quot;/docs/core-concepts/statics&quot;&gt;statics&lt;/a&gt;-- like &lt;code&gt;Brioche.gitCheckout&lt;/code&gt;-- can reference the &lt;code&gt;project&lt;/code&gt; export.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This approach is both simple and powerful, making it easy to add pre-built live-update scripts from a variety of sources, or project-specific ones as needed. And &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; has been hard at work adding pre-built live-update scripts &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/tree/main/packages/std/extra/live_update&quot;&gt;for a &lt;em&gt;bunch&lt;/em&gt; of common package sources&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Faster bulk checking and formatting of packages&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;brioche check&lt;/code&gt; and &lt;code&gt;brioche fmt&lt;/code&gt; can both take multiple packages to work on in bulk, &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.2&quot;&gt;since Brioche v0.1.2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Well, now, both have been re-worked: both commands now load and handle all the projects in bulk too, rather than just processing them one by one. For &lt;code&gt;brioche check&lt;/code&gt; especially, this can be a &lt;em&gt;huge&lt;/em&gt; improvement! Back when &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/255&quot;&gt;PR #255&lt;/a&gt; was opened, I measured the time it took to call &lt;code&gt;brioche check&lt;/code&gt; with all the packages from the &lt;code&gt;brioche-packages&lt;/code&gt; repo, and it went from &lt;strong&gt;6 minutes 1 second&lt;/strong&gt; to just &lt;strong&gt;7.5 seconds&lt;/strong&gt;-- that&apos;s &lt;strong&gt;48 times faster&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;(the actual speed improvement will be proportional to the number of projects you&apos;re checking, though!)&lt;/p&gt;
&lt;h2&gt;Lazy building (experimental)&lt;/h2&gt;
&lt;p&gt;The main build job in the Brioche Packages CI pipeline boils down to a simple loop-- basically:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for package in package/*; do
  brioche build -p &quot;$package&quot; --sync --locked
done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unintuitively, this ended up wasting a &lt;em&gt;lot&lt;/em&gt; of time and bandwidth. That&apos;s because, today, &lt;code&gt;brioche build&lt;/code&gt; always ensures the build result exists locally (either building it, or pulling it from the cache). In other words, we were fetching the output for &lt;em&gt;every&lt;/em&gt; package on &lt;em&gt;every&lt;/em&gt; CI run, even if the package was already up-to-date in the remote cache!&lt;/p&gt;
&lt;p&gt;I ruled out updating our CI pipeline to look at which files changed. It&apos;s not specific enough for our needs, since we&apos;d also want to re-run if a dependent package changed too. It also creates awkward issues and failure cases if earlier CI builds failed.&lt;/p&gt;
&lt;p&gt;Instead, I added a new flag for &lt;code&gt;brioche build&lt;/code&gt;: &lt;code&gt;--experimental-lazy&lt;/code&gt;. Basically, it first checks if the build result exists in the remote cache, and skips doing anything else if it does. It avoids the useless pulling from the cache that we don&apos;t want!&lt;/p&gt;
&lt;p&gt;I added it as a new build flag for now; mostly because the implementation was a bit hacky and awkward, and partially because I felt like the old behavior of pulling the cache results &lt;em&gt;could&lt;/em&gt; be useful in some cases. I also still feel this flag is experimental (hopefully that&apos;s clear from the name)! A few thoughts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The name is not final of course. It could be renamed to &lt;code&gt;--lazy&lt;/code&gt; (or some other name)&lt;/li&gt;
&lt;li&gt;...or, in the future, we could make this the default behavior of &lt;code&gt;brioche build&lt;/code&gt; (possibly with, say, an inverse &lt;code&gt;--pull&lt;/code&gt; flag to always pull the result from the cache)&lt;/li&gt;
&lt;li&gt;The behavior is also not final. It doesn&apos;t exactly play well with other flags like &lt;code&gt;-o&lt;/code&gt; / &lt;code&gt;--output&lt;/code&gt; today&lt;/li&gt;
&lt;li&gt;We&apos;ve been using this for a while now in the Brioche Packages repo, and so far nothing has broken terribly!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Lazy publishing&lt;/h2&gt;
&lt;p&gt;The basic flow of the Brioche Packages CI pipeline basically does this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check each package&lt;/li&gt;
&lt;li&gt;Build each package&lt;/li&gt;
&lt;li&gt;Publish each package&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&apos;ve already talked about how we&apos;ve sped up &lt;a href=&quot;#faster-bulk-checking-and-formatting-of-packages&quot;&gt;checking&lt;/a&gt; and &lt;a href=&quot;#lazy-building-experimental&quot;&gt;building&lt;/a&gt;, but we&apos;ve also sped up publishing!&lt;/p&gt;
&lt;p&gt;Each time we ran &lt;code&gt;brioche publish&lt;/code&gt;, Brioche would first run checks against the package. But by the time we reached step (3) in the workflow, we&apos;ve already run &lt;code&gt;brioche check&lt;/code&gt; on each package in step (1), so this check was redundant. And worse, &lt;code&gt;brioche publish&lt;/code&gt; doesn&apos;t support taking multiple packages to publish (today), so each of these checks were run sequentially, just like we had been doing before.&lt;/p&gt;
&lt;p&gt;So, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; added the new &lt;code&gt;--no-verify&lt;/code&gt; flag for the &lt;code&gt;brioche publish&lt;/code&gt; command (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/326&quot;&gt;PR #326&lt;/a&gt;). As the name implies, it skips over the checks we do before publishing. This sped up the &quot;publish&quot; step in our CI pipeline roughly from &lt;strong&gt;30 minutes&lt;/strong&gt; to &lt;strong&gt;3 minutes&lt;/strong&gt;-- that&apos;s &lt;strong&gt;900% faster&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;(again, it&apos;s actually proportional to the number of projects you&apos;re trying to publish! also please don&apos;t use it unless you&apos;re already calling &lt;code&gt;brioche check&lt;/code&gt; first!!)&lt;/p&gt;
&lt;h2&gt;Shorthand (non-function) exports&lt;/h2&gt;
&lt;p&gt;Let&apos;s look at a basic Brioche project (based roughly on our &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/32357428b11a8f1b511ef03ccd6d01b96930b8c7/examples/rust_backend/project.bri&quot;&gt;&lt;code&gt;rust_backend&lt;/code&gt; example project&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as std from &quot;std&quot;;
import { cargoBuild } from &quot;rust&quot;;

export default function () {
  return cargoBuild({
    source: Brioche.glob(&quot;src&quot;, &quot;Cargo.*&quot;),
    runnable: &quot;bin/rust_backend&quot;,
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The meat and potatoes of our build is wrapped within the &lt;code&gt;export default function () { }&lt;/code&gt;. But having to wrap our build in an extra function doesn&apos;t seem to be super helpful here, does it?&lt;/p&gt;
&lt;p&gt;Well, now you get rid of the &lt;code&gt;function&lt;/code&gt; wrapper, if you&apos;d like!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as std from &quot;std&quot;;
import { cargoBuild } from &quot;rust&quot;;

export default cargoBuild({
  source: Brioche.glob(&quot;src&quot;, &quot;Cargo.*&quot;),
  runnable: &quot;bin/rust_backend&quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both snippets are effectively the same now, so it really comes down to personal preference for which style you go with. For Brioche Packages, we&apos;ll likely stick with the existing wrapper functions for a number of reasons (specifying the type of the recipe, giving the function a module-local name for use with tests, deferring work until a recipe is evaluated). But I have some ideas for future features where non-function exports could be a big improvement for ergonomics, plus I think this change makes things more consistent!&lt;/p&gt;
&lt;h2&gt;Release process changes&lt;/h2&gt;
&lt;p&gt;Our release process for Brioche went through a massive overhaul during this release, stemming from &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/281&quot;&gt;PR #281&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, the new release structure isn&apos;t compatible with the pre-existing self-update process-- sorry about that! Whether you have an existing installation of Brioche or not, check the &lt;a href=&quot;/docs/installation&quot;&gt;&quot;Installation&quot; docs&lt;/a&gt; for details on installing the latest release.&lt;/p&gt;
&lt;p&gt;This is mostly an internal change, and one that should make it easier to get new releases out faster. But there are a few interesting things that you might notice from the outside too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Releases are now signed! Both the installer and self-updater will validate the signature against our &quot;release&quot; public key before installing.&lt;/li&gt;
&lt;li&gt;Releases are now &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/352&quot;&gt;attested&lt;/a&gt;, too. We don&apos;t do any validation around the attestation (today), but this gives strong guarantees about how the release artifacts were built. Check out GitHub&apos;s docs on &lt;a href=&quot;https://docs.github.com/en/actions/concepts/security/artifact-attestations&quot;&gt;artifact attestation&lt;/a&gt; for more context.&lt;/li&gt;
&lt;li&gt;We&apos;ve now moved entirely over to &lt;a href=&quot;/blog/announcing-brioche-v0-1-4#packed-builds-of-brioche&quot;&gt;&quot;packed builds&quot;&lt;/a&gt;, finally! (Unpacked builds are still included with nightly releases though)&lt;/li&gt;
&lt;li&gt;The release artifacts are distributed as &lt;code&gt;.tar.xz&lt;/code&gt; files, meaning they&apos;re smaller (and therefore quicker to download)!&lt;/li&gt;
&lt;li&gt;The install script now lives in its own repo: &lt;a href=&quot;https://github.com/brioche-dev/brioche-installer&quot;&gt;&lt;code&gt;brioche-installer&lt;/code&gt;&lt;/a&gt; (still missing a README + docs at the time of writing, but hopefully that will change soon)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;Well, this release ended up including a lot more than I was expecting... but it makes sense since it&apos;s been over 6 months since our last release.&lt;/p&gt;
&lt;p&gt;Going forward, I&apos;m aiming for smaller, more frequent releases, so expect less exciting announcements! The new release process should make it &lt;em&gt;much&lt;/em&gt; easier to get new releases out the door. Plus, if you didn&apos;t see the news from the last project update, I&apos;m now &lt;a href=&quot;/blog/project-update-2025-10#officially-working-part-time-on-brioche&quot;&gt;working on Brioche part-time&lt;/a&gt;!&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - October 2025</title><link>https://brioche.dev/blog/project-update-2025-10</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-10</guid><pubDate>Thu, 30 Oct 2025 21:58:04 GMT</pubDate><content:encoded>&lt;p&gt;This month has been a really exciting one... both for Brioche, and for me personally!&lt;/p&gt;
&lt;p&gt;Oh, and this month we also crossed 300 total packages! 🎉&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Officially working part-time on Brioche!!&lt;/h3&gt;
&lt;p&gt;Even before &lt;a href=&quot;/blog/announcing-brioche&quot;&gt;it&apos;s initial announcement&lt;/a&gt;, I&apos;ve worked on Brioche as a side project, working on it on nights and weekends. Making time to work on Brioche outside my dayjob as a full-stack developer while keeping enough downtime to not burn myself out has been a challenge, to say the least!&lt;/p&gt;
&lt;p&gt;Well, as of this month, I&apos;ve since &lt;strong&gt;switched from working from full-time to part-time at my dayjob&lt;/strong&gt; (now as an independent contractor). So now, I work 3 days a week as my source of income, and I currently spend &lt;strong&gt;2 days a week dedicated to Brioche&lt;/strong&gt;! That frees up my weekends for resting or socializing or other side projects or other hobbies (or, to be honest, more work on Brioche-- but I&apos;m trying to get better at letting myself &lt;em&gt;not&lt;/em&gt; work on Brioche whenever I have free time)!&lt;/p&gt;
&lt;p&gt;I&apos;m really really excited about this and there&apos;s a ton more I could say!! But a few major ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&apos;m still funding Brioche out of my own pocket. Most of our recurring costs are from hosting the cache and registry (our build machines are self-hosted in our homelab).&lt;/li&gt;
&lt;li&gt;Even with my reduced income &lt;em&gt;and&lt;/em&gt; paying for Brioche resources, our household finances are still sustainable for the forseeable future.&lt;/li&gt;
&lt;li&gt;...but this arrangement probably won&apos;t be sustainable for me &lt;em&gt;forever&lt;/em&gt;. Realistically, I&apos;ll probably go back to working full-time again someday.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Now taking donations / sponsorships!&lt;/h3&gt;
&lt;p&gt;Since I&apos;m now working on Brioche as my part-time job (effectively), I felt it was finally the right time to start accepting patronage. If you&apos;re interested in pitching in, I can take your money thorough either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://liberapay.com/brioche-dev/&quot;&gt;Liberapay&lt;/a&gt; (a Liberapay &quot;team&quot; for Brioche, which right now just has me)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sponsors/kylewlacy&quot;&gt;GitHub Sponsors&lt;/a&gt; (my personal profile)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(there&apos;s already a few links on the website pointing to both platforms-- including on the new &lt;a href=&quot;/get-involved&quot;&gt;Get Involved&lt;/a&gt; page!-- but it&apos;s not consistent everywhere yet, so more links for both will probably show up in a few places)&lt;/p&gt;
&lt;p&gt;I&apos;m hoping that, as Brioche grows, a few folks would be willing to chip in enough to partially or fully cover Brioche&apos;s recurring costs, or even to pay for more self-hosted hardware-- like more build machines. Or if Brioche becomes a big success one day, it&apos;d be a dream if those sponsorships could even sustain me for &lt;em&gt;full-time&lt;/em&gt; work on Brioche indefinitely, or eventually be enough to pay to bring on other contributors part-time or full-time!&lt;/p&gt;
&lt;p&gt;Small aside: this is something I&apos;ve considered for a long time, but soliciting donations is something that I&apos;ve felt a tinge of guilt around-- I&apos;m not sure why to be honest! But switching to part-time was enough of a push for me to finally go and get it set up. I&apos;m staunchly against taking VC funding or other investments for Brioche, so asking for donations is the first step on the path to making Brioche sustainable long-term.&lt;/p&gt;
&lt;h3&gt;New docs for contributors&lt;/h3&gt;
&lt;p&gt;I added a few docs geared towards potential contributors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/docs/contributing/overview&quot;&gt;&quot;Contributor&apos;s Overview&quot;&lt;/a&gt;: A breakdown of the different repos and structure of Brioche. Should help interested folks get their bearings and help them decide what to contribute to.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/contributing/packaging-guide&quot;&gt;&quot;Packaging Guide&quot;&lt;/a&gt;: Some general details on how to contribute new packages, with some specifics for a few common languages / ecosystems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both pages are sort of a &quot;first pass&quot;, and I think both could use improvement / iteration (if you have ideas to improve them, contributions are welcome in the &lt;a href=&quot;https://github.com/brioche-dev/brioche.dev&quot;&gt;&lt;code&gt;brioche.dev&lt;/code&gt; repo&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;I also added a new &lt;a href=&quot;/get-involved&quot;&gt;&quot;Get Involved!&quot;&lt;/a&gt; page. This was meant to be a catch-all for folks that would be interested in discussing Brioche (links to Zulip/Discord/GitHub Discussions), contributing to Brioche (links to docs pages on contributing), or supporting Brioche (links to Liberapay + GitHub Sponsors). I always wanted to link to more things in the header, but it&apos;s kinda space-constrained especially on mobile, so this was what I came up as an &quot;umbrella&quot; to cover multiple semi-related links at once.&lt;/p&gt;
&lt;h3&gt;Build Python with optimizations&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened a PR to enable compiler optimizations and LTO for our &lt;code&gt;python&lt;/code&gt; package: &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1522&quot;&gt;&lt;code&gt;brioche-dev/brioche-packages#1522&lt;/code&gt;&lt;/a&gt;. A small change (and one that&apos;s makes our CI runners sweat!), but a nice improvement for folks that use Python through Brioche!&lt;/p&gt;
&lt;h3&gt;More consistency fixes in &lt;code&gt;brioche-packages&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; got a &lt;em&gt;lot&lt;/em&gt; of PRs in to help fix miscellaneous issues in &lt;code&gt;brioche-packages&lt;/code&gt;-- especially issues related to absolute paths and to live-update scripts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure &lt;code&gt;std.pkgConfigMakePathsRelative&lt;/code&gt; and &lt;code&gt;std.libtoolSanitizeDependencies&lt;/code&gt; follow symlinks (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1536&quot;&gt;#1536&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add functions for live-updates from Gitea, GitLab, Go modules, and Python PyPI packages (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1532&quot;&gt;#1532&lt;/a&gt;, &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1468&quot;&gt;#1468&lt;/a&gt;, &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1396&quot;&gt;#1396&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix &lt;code&gt;freetype&lt;/code&gt; so &lt;code&gt;freetype-config&lt;/code&gt; uses relative paths (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1530&quot;&gt;#1530&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;ACLOCAL_PATH&lt;/code&gt; when relevant (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1411&quot;&gt;#1411&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add package test for &lt;code&gt;linux&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1402&quot;&gt;#1402&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Remove unused env vars from &lt;code&gt;re2c&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1355&quot;&gt;#1355&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Remove unused CMake from &lt;code&gt;bubblewrap&lt;/code&gt; build (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1392&quot;&gt;#1392&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oh, and we had some discussions around the &lt;code&gt;.pipe()&lt;/code&gt; method, and landed on our preferered style:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Preferred:
recipe.pipe(function1).pipe(function2);

// ...instead of:
// recipe.pipe(
//   function1,
//   function2,
// );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the discssion in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1594&quot;&gt;#1594&lt;/a&gt; for more context&lt;/p&gt;
&lt;h3&gt;Some packages CI / repo improvements&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; added some PR templates for adding / updating packages in the &lt;code&gt;brioche-packages&lt;/code&gt; repo: https://github.com/brioche-dev/brioche-packages/tree/main/.github/PULL_REQUEST_TEMPLATE (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/tree/ff3526010e7e086147574dd2fbf09e07c6adc07c/.github/PULL_REQUEST_TEMPLATE&quot;&gt;permalink&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;GitHub doesn&apos;t support templates for PRs (today), but this will be useful to help new contributors make sure everything that&apos;s needed is in place for a new package!&lt;/p&gt;
&lt;p&gt;Also, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; got some fixes in to the CI pipeline itself to check for formatting (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1417&quot;&gt;#1417&lt;/a&gt;), and to skip checks during the &quot;publishing&quot; step (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1413&quot;&gt;#1413&lt;/a&gt;)-- which will help get new packages and package updates released faster!&lt;/p&gt;
&lt;h3&gt;Installer &amp;amp; release work&lt;/h3&gt;
&lt;p&gt;It&apos;s been a while since &lt;a href=&quot;https://brioche.dev/blog/announcing-brioche-v0-1-5/&quot;&gt;the last Brioche release back in April&lt;/a&gt;. There haven&apos;t been any &lt;em&gt;huge&lt;/em&gt; new features, but there have been a few minor fixes-- and &lt;code&gt;linux-aarch64&lt;/code&gt; support!-- so it&apos;d be nice to get a new release out.&lt;/p&gt;
&lt;p&gt;...that&apos;s how I&apos;ve felt for a while, but the current release process is pretty painful, with a lot of manual steps. So, I worked on cleaning up the mess that was our release process, and almost all the pieces are in place now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restructure build artifacts to unify packed / unpacked builds (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/281&quot;&gt;#281&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Sign binaries we build in CI (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/281&quot;&gt;#281&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Restructure release/update metadata in &lt;code&gt;https://releases.brioche.dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Update self-updater to use new metadata format and to check signatures during updates (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/281&quot;&gt;#281&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Create separate repo for installer script: https://github.com/brioche-dev/brioche-installer&lt;/li&gt;
&lt;li&gt;(&lt;em&gt;In progress&lt;/em&gt;) Add automated CI pipeline for releases&lt;/li&gt;
&lt;li&gt;(&lt;em&gt;Post-release&lt;/em&gt;) Update website to serve new installer script&lt;/li&gt;
&lt;li&gt;(&lt;em&gt;Post-release&lt;/em&gt;) Update &lt;code&gt;setup-brioche&lt;/code&gt; action to directly use new installer script&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As part of that work, I did publish a new prerelease build of Brioche: &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.6-rc.2&quot;&gt;v0.1.6-rc.2&lt;/a&gt; (don&apos;t ask what happened to rc.1). This isn&apos;t intended to be used directly, but was meant to kick the tires on the new work-in-progress automated release pipeline. There&apos;ll also probably be one or more prereleases like this as a final pass.&lt;/p&gt;
&lt;p&gt;Anyway, the hard parts should all be in place now. I&apos;m really happy with how smooth the new release pipeline is turning out! Brioche v0.1.6 should be coming really soon!&lt;/p&gt;
&lt;h3&gt;Issues galore!&lt;/h3&gt;
&lt;p&gt;I spent some time just opening issues for miscellaneous Brioche ideas and improvements. For me, this is helpful to keep track on what I want to work on next, to have things to link to when discussing Brioche features, and to help give others an idea on the direction Brioche is heading. Plus, it&apos;s useful for collaboration in case others want to help out (I try to write pretty detailed issues!), and for gathering discussion.&lt;/p&gt;
&lt;p&gt;If you have any feedback, please don&apos;t hesitate to comment on any open issues! A few that I&apos;d like to call out that could use some discussion/feedback/ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependencies / imports via git repos (&lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/333&quot;&gt;#333&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Unified CLI syntax for projects/packages/exports (&lt;a href=&quot;https://github.com/brioche-dev/brioche/discussions/320&quot;&gt;#320&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Spawn recipes within recipes (sccache-like builds) (&lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/343&quot;&gt;#343&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Overhaul &lt;code&gt;brioche jobs&lt;/code&gt; command (&lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/339&quot;&gt;#339&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Support locking things in the lockfile using user-defined functions (&lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/353&quot;&gt;#353&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;WebAssembly-based sandboxing (&lt;a href=&quot;https://github.com/brioche-dev/brioche/discussions/322&quot;&gt;#322&lt;/a&gt;, not opened by me but still wanted to highlight it!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;50&lt;/strong&gt; new packages&lt;/p&gt;
&lt;p&gt;During October, we just crossed a huge milestone: &lt;strong&gt;we now have over 300 packages total!!!&lt;/strong&gt; 🎉&lt;/p&gt;
&lt;p&gt;New packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aks_mcp_server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bacon&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_binutils&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_bisect_rustc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_c&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_deny&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_edit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_expand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_flamegraph&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_fuzz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_generate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_llvm_lines&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_machete&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_make&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_outdated&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_release&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_smart_release&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ck_search&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;duktape&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gitea_mcp_server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;github_copilot_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;github_mcp_server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;json_c&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lcms2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libsrtp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libtiff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libvpx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxaw&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxext&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxfixes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxmu&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxrandr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxrender&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxtst&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lint_staged&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mpdecimal&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opus&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;promptfoo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rust_analyzer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sendme&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;skim&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slang&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;terraform_mcp_server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;typst&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;velero&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wakatime_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xxhash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yasm&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/314&quot;&gt;#314&lt;/a&gt;: Update GitHub CI&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/315&quot;&gt;#315&lt;/a&gt;: ci: update workflow to use runs-on instead of runs_on&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/316&quot;&gt;#316&lt;/a&gt;: ci: update workflow to use matrix include syntax&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/317&quot;&gt;#317&lt;/a&gt;: refactor(ci): use latest version of &lt;code&gt;brioche-dev/setup-brioche&lt;/code&gt; to simplify Brioche installation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/323&quot;&gt;#323&lt;/a&gt;: build: update object_store to version 0.12.4&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/281&quot;&gt;#281&lt;/a&gt;: Sign and restructure built binaries&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/324&quot;&gt;#324&lt;/a&gt;: Switch to &lt;code&gt;xz&lt;/code&gt; for Brioche release artifacts&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/326&quot;&gt;#326&lt;/a&gt;: Add publish args to skip some checks when used in CI&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/335&quot;&gt;#335&lt;/a&gt;: build: update opentelemetry dependencies to latest versions&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/336&quot;&gt;#336&lt;/a&gt;: build: remove assert_matches from dependencies, add to dev-dependencies&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/337&quot;&gt;#337&lt;/a&gt;: Small tweaking here and there&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/342&quot;&gt;#342&lt;/a&gt;: Add internal post-install step for Brioche installation and updates&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/338&quot;&gt;#338&lt;/a&gt;: Update efficiency of format command when working with multiple projects&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/345&quot;&gt;#345&lt;/a&gt;: build: remove target setup from rust toolchain toml file&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/346&quot;&gt;#346&lt;/a&gt;: Update Dependabot config&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/352&quot;&gt;#352&lt;/a&gt;: Update CI to attest artifacts&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - September 2025</title><link>https://brioche.dev/blog/project-update-2025-09</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-09</guid><pubDate>Mon, 29 Sep 2025 01:30:29 GMT</pubDate><content:encoded>&lt;p&gt;This month has seen some very nice improvements that span multiple packages, some OpenTelemetry improvements, and some yak shaving&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;CMake build improvements&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; got a change in for CMake builds in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1144&quot;&gt;#1144&lt;/a&gt;, which uses &lt;code&gt;workDir&lt;/code&gt; for the CMake build directory. With this change, the source directory is now writable during the build-- previously, the source directory was read-only, which caused problems for some packages.&lt;/p&gt;
&lt;p&gt;This resolved &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/issues/677&quot;&gt;#677&lt;/a&gt;, which has been outstanding for a while&lt;/p&gt;
&lt;h3&gt;More build parallelism&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1149&quot;&gt;#1149&lt;/a&gt; and &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1194&quot;&gt;#1194&lt;/a&gt; to update all of our &lt;code&gt;make&lt;/code&gt;-based builds to build in parallel where possible, using &lt;code&gt;make -j &quot;$(nproc)&quot;&lt;/code&gt;. This can make a big difference both when testing changes locally and when getting changes deployed through CI!&lt;/p&gt;
&lt;p&gt;And on the same track, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1149&quot;&gt;#1149&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1195&quot;&gt;#1195&lt;/a&gt; too, which &lt;em&gt;automatically&lt;/em&gt; does the same thing for all CMake-based builds-- well, those using the &lt;code&gt;cmakeBuild&lt;/code&gt; function at least! This behavior can also be manually overridden still (see the PR for details).&lt;/p&gt;
&lt;h3&gt;libtool / pkg-config fixes&lt;/h3&gt;
&lt;p&gt;We&apos;ve had the function &lt;code&gt;std.pkgConfigMakePathsRelative()&lt;/code&gt; around for a while-- you can think of it like a post-processing / cleanup step to fix-up pkg-config files in a package, so paths are resolved properly when used as a dependency for other packages. This is needed because most software projects out in the world use absolute paths in their pkg-config files, while Brioche &lt;em&gt;really&lt;/em&gt; needs relative paths. libtool files has the same problem: they often use absolute paths, while we&apos;d really prefer they didn&apos;t.&lt;/p&gt;
&lt;p&gt;So, I pulled a report of all libtool files across all packages, and &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened some PRs to get those fixed as well: &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1286&quot;&gt;#1286&lt;/a&gt;, &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1288&quot;&gt;#1288&lt;/a&gt;, and &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1290&quot;&gt;#1290&lt;/a&gt;. Now, we use the new &lt;code&gt;std.libtoolSanitizeDependencies()&lt;/code&gt; as needed, which automatically fixes any libtool files we find in a package!&lt;/p&gt;
&lt;p&gt;Oh, and &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1287&quot;&gt;#1287&lt;/a&gt; also added some calls to &lt;code&gt;std.pkgConfigMakePathsRelative()&lt;/code&gt; for some packages that were missing it, too.&lt;/p&gt;
&lt;h3&gt;X11 libraries&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; has been on a tear adding a bunch of X.org packages lately. There&apos;s been incremental progress lately towards supporting GUI-based packages in Brioche, and this continues the same theme. A major milestone we just hit was with the &lt;code&gt;libx11&lt;/code&gt; package, which was just added recently in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1291&quot;&gt;#1291&lt;/a&gt;!&lt;/p&gt;
&lt;h3&gt;OpenTelemetry improvements&lt;/h3&gt;
&lt;p&gt;At the end of last month (just after the window of the last Project Update), I spent some time cleaning up Brioche&apos;s built-in OpenTelemetry / tracing output in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/305&quot;&gt;#305&lt;/a&gt;. &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; also opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/306&quot;&gt;#306&lt;/a&gt; to export logs as OpenTelemetry logs (previously, we wrote logs only as events instead). Together, these changes should make it much easier to trace Brioche using tools like Grafana&apos;s &lt;a href=&quot;https://github.com/grafana/docker-otel-lgtm&quot;&gt;LGTM stack&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Yak shaving: instrumentation tools&lt;/h3&gt;
&lt;p&gt;I took a small detour this month a made a few small debugging / instrumentation tools. Are these related to Brioche? Not directly, but these tools were meant to help with Brioche-related tasks-- and I think there&apos;s a chance we&apos;ll have some of this tooling integrated in Brioche one day!&lt;/p&gt;
&lt;p&gt;Background context: Brioche doesn&apos;t have much built-in tooling for debugging a failed build. We have &lt;a href=&quot;/blog/project-update-2024-11/#new-process-logging&quot;&gt;process output logs&lt;/a&gt;, a &lt;a href=&quot;/blog/project-update-2025-03/#debug-shell-for-failed-jobs&quot;&gt;debug shell&lt;/a&gt;, and direct access to the files from the failed sandbox. Beyond that, I often use &lt;a href=&quot;https://strace.io/&quot;&gt;strace&lt;/a&gt;-- a tool that records all the syscalls of a process-- which is &lt;em&gt;extremely&lt;/em&gt; useful for figuring out which command deep in a build failed, what library or file couldn&apos;t be found, etc.&lt;/p&gt;
&lt;p&gt;But strace can be pretty hard to parse! So I wrote a little tool called &lt;a href=&quot;https://github.com/kylewlacy/systrument&quot;&gt;systrument&lt;/a&gt;. It basically parses strace&apos;s output, and converts it to a structured, graphical format:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./project-update-2025-09/systrument-grafana-tempo.png&quot; alt=&quot;Screenshot of Grafana, showing a timeline of executed processes. The top-level is called &amp;quot;systrument&amp;quot;, and &amp;quot;brioche&amp;quot; is below that. Below that are various build-related processes, including &amp;quot;sh&amp;quot;, &amp;quot;bash&amp;quot;, and &amp;quot;configure&amp;quot;.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;bg-gray-200 dark:bg-gray-700 px-4 py-4 rounded-lg&quot;&amp;gt;
I also recently came across this list of &lt;a href=&quot;https://github.com/oils-for-unix/oils/wiki/Process-Tracing-Projects&quot;&gt;&quot;Process Tracing
Projects&quot;&lt;/a&gt;,
with other similar projects!
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;I haven&apos;t gotten much use out of this tool yet, but from the little I&apos;ve played with it, I&apos;m hoping it&apos;ll pay dividends for diagnosing build errors. If it does, I think it&apos;d be neat for a similar tool to be integrated in Brioche directly, similar in spirit to &lt;a href=&quot;https://ninja-build.org/manual.html#ref_log&quot;&gt;Ninja&apos;s log file&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Shifting gears, a totally unrelated problem: we have a very small pool of CI runners for building packages-- one aarch64 runner and one x86-64 runner. Since Brioche doesn&apos;t support cross-compilation yet, every package needs to be built on both runners before being published.&lt;/p&gt;
&lt;p&gt;I wanted to visualize how our runners are running. In the short term, this could potentially help spot low-hanging fruit; in the medium-to-long term, it&apos;ll help to figure out build machine utilization, which will help us provision more build machines.&lt;/p&gt;
&lt;p&gt;So I wrote &lt;a href=&quot;https://github.com/kylewlacy/ci-instrument&quot;&gt;ci-instrument&lt;/a&gt;, which calls the GitHub API and produces a file that can be loaded into the &lt;a href=&quot;https://ui.perfetto.dev/&quot;&gt;Perfetto UI&lt;/a&gt; to show GitHub Actions jobs over time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./project-update-2025-09/ci-instrument-perfetto.png&quot; alt=&quot;Perfetto UI showing a timeline of GitHub Actions jobs. A job named &amp;quot;Build / build / Build packages [x86_64-linux]&amp;quot; is selected, showing metadata about the build and a link to the GitHub workflow run.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s really cool to be able to see visually where the bottlenecks are in our build pipelines, and to see which package builds are slowest!&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;19&lt;/strong&gt; new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cargo_tarpaulin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eslint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;go_task&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;igrep&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libdnet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libnet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libx11&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxcb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxdmcp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxpm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tenv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;terraform_docs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;terraform_ls&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;traefik&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tree_sitter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unixodbc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;usage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xcb_proto&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/303&quot;&gt;#303&lt;/a&gt;: Fix panic when enabling OpenTelemetry output&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/305&quot;&gt;#305&lt;/a&gt;: Improve OpenTelemetry output&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/306&quot;&gt;#306&lt;/a&gt;: feat(otel): refactor the code and add logging exporting&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/307&quot;&gt;#307&lt;/a&gt;: Continue to resolve Clippy pedantic lints&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/309&quot;&gt;#309&lt;/a&gt;: build: update Rust version to 1.90&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/310&quot;&gt;#310&lt;/a&gt;: chore(clippy): add unreadable_literal lint to Cargo.toml&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/311&quot;&gt;#311&lt;/a&gt;: Upgrade Brioche-in-Brioche dependencies&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/312&quot;&gt;#312&lt;/a&gt;: Allow setting hash algorithm for HashSet/HashMap&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/313&quot;&gt;#313&lt;/a&gt;: Resolve all the pedantic lints&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - August 2025</title><link>https://brioche.dev/blog/project-update-2025-08</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-08</guid><pubDate>Fri, 29 Aug 2025 03:11:40 GMT</pubDate><content:encoded>&lt;p&gt;Not a lot of new headliner features made it in this month, but lots of little incremental improvements have been piling up!&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Set up merge queues for CI&lt;/h3&gt;
&lt;p&gt;Each Friday, we run an automated GitHub Actions workflow for &quot;live updates&quot;, where scripts check for new upstream package versions, then create separate PRs for each package. Each PR would trigger a build immediately, and could be merged after being reviewed and after a successful build.&lt;/p&gt;
&lt;p&gt;But this setup started causing a &quot;traffic jam&quot;, especially since the number of packages has been steadily growing! We only have one CI runner for each of &lt;code&gt;x86_64&lt;/code&gt; and &lt;code&gt;aarch64&lt;/code&gt; today, so triggering builds both when these live-update PRs open &lt;em&gt;and&lt;/em&gt; when they were merged was slow, and could create a lot of wasteful / unused build results. Not to mention, if there were breakages between 2 new updated packages, we&apos;d only find out when the &lt;code&gt;main&lt;/code&gt; branch would fail-- which would then block any new packages or updates from going out as well!&lt;/p&gt;
&lt;p&gt;We hit a particularly bad case starting August 8th: it took probably 36 hours to work through all the queued build jobs! That weekend, I &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1015&quot;&gt;updated &lt;code&gt;brioche-packages&lt;/code&gt; to use merge queues instead&lt;/a&gt;. This was my first time using GitHub&apos;s merge queue feature-- I think it&apos;s kinda confusing... but getting this in has been really helpful for improving our CI!&lt;/p&gt;
&lt;p&gt;Basically, live-update PRs never trigger builds anymore. Instead, &lt;em&gt;every&lt;/em&gt; PR gets &quot;queued&quot; before merging, which is where we do the actual build. If the build passes, only then do we push to &lt;code&gt;main&lt;/code&gt;, which then publishes the packages to the Brioche Registry. This avoids some &quot;wasted&quot; builds that are never published, prevents &lt;code&gt;main&lt;/code&gt; from ever being broken due to conflicts between new versions, and gives us tools like limiting concurrent builds, rearranging PRs in the queue, etc. It&apos;s not a perfect setup, but it&apos;s a big improvement!&lt;/p&gt;
&lt;h3&gt;&quot;Lazy builds&quot; for CI&lt;/h3&gt;
&lt;p&gt;For builds, our CI pipeline basically just runs &lt;code&gt;brioche build -p ./package/${package_name}&lt;/code&gt; for each package. Build results are cached of course, but this still ends up being pretty wasteful because &lt;code&gt;brioche build&lt;/code&gt; &lt;em&gt;always&lt;/em&gt; makes sure the build result is available-- downloading it from the cache if it doesn&apos;t exist locally.&lt;/p&gt;
&lt;p&gt;Oh, and even though the new merge queue setup ensures PRs are built before reaching &lt;code&gt;main&lt;/code&gt;, we still call &lt;code&gt;brioche build&lt;/code&gt; for each package before publishing (that lets us still push fixes directly to &lt;code&gt;main&lt;/code&gt; without going through the PR process, but that&apos;s a last-resort measure). But that also means each PR will fetch every package from the cache &lt;em&gt;twice&lt;/em&gt; before publishing!&lt;/p&gt;
&lt;p&gt;This was slowing down builds somewhat and wasting a little money each month for our cache cloud costs. As a quick-and-dirty workaround, I added a new &lt;code&gt;--experimental-lazy&lt;/code&gt; flag in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/294&quot;&gt;&lt;code&gt;brioche#294&lt;/code&gt;&lt;/a&gt;. When running &lt;code&gt;brioche build&lt;/code&gt;, this flag first checks if the build result exists in the remote cache, then returns early if it does. We now always use this flag for &lt;code&gt;brioche-packages&lt;/code&gt; builds, so this saves a ton of time and bandwidth wasted fetching packages unnecessarily from the cache.&lt;/p&gt;
&lt;p&gt;My gut feeling right now is that we should make this behavior the default eventually. Actually, the reason I didn&apos;t make it the default yet was because I want to do some internal refactoring to make this change more natural first (the current implementation actually checks the cache twice and can only short-circuit the top-level build-- these are both not ideal but are consequences due to how builds are currently handled, and I think reworking some stuff could make &quot;lazy builds&quot; the default, basically).&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;object_store&lt;/code&gt; update for better retry logic&lt;/h3&gt;
&lt;p&gt;Back in July, &lt;a href=&quot;https://github.com/nz366&quot;&gt;&lt;strong&gt;@nz366&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/286&quot;&gt;&lt;code&gt;brioche#286&lt;/code&gt;&lt;/a&gt; to improve the retry logic when encountering network errors when fetching from the cache.&lt;/p&gt;
&lt;p&gt;Well, it turns out that the the upstream &lt;code&gt;object_store&lt;/code&gt; crate had a bug that prevented retrying requests due to connection errors, which was fixed in &lt;a href=&quot;https://github.com/apache/arrow-rs-object-store/pull/445&quot;&gt;this PR&lt;/a&gt;. So once the new version of &lt;code&gt;object_store&lt;/code&gt; was released, &lt;a href=&quot;https://github.com/nz366&quot;&gt;&lt;strong&gt;@nz366&lt;/strong&gt;&lt;/a&gt; opeend &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/287&quot;&gt;&lt;code&gt;brioche#287&lt;/code&gt;&lt;/a&gt;, which just bumped &lt;code&gt;object_store&lt;/code&gt; to the new version that included the upstream fix.&lt;/p&gt;
&lt;p&gt;Sometimes it stings to see a code change thrown away because you tried to fix something &lt;em&gt;too&lt;/em&gt; fast... but we got the retry improvements in the end either way!&lt;/p&gt;
&lt;h3&gt;Even more live-update improvements&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; has continued with lots of improvements to the live-update scripts, which helps us keep as many packages up-to-date with as little friction as possible! A few specific PRs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/974&quot;&gt;#974&lt;/a&gt;: Add validation to version matching regex&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1098&quot;&gt;#1098&lt;/a&gt;: Refactor projects with multiple versions for consistency and ease of updates&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/1103&quot;&gt;#1103&lt;/a&gt;: Update GitHub live-update scripts to support updating multiple simultaneous package versions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;20&lt;/strong&gt; new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;coturn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cspell&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dclint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deno&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gopls&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hugo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hunspell&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keep_sorted&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libice&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libsm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxau&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxcrypt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mutagen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nuspell&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;socat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;terragrunt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xorgproto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xtrans&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This month, we had quite a few people to &lt;code&gt;brioche-packages&lt;/code&gt;! Thanks to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/easrng&quot;&gt;&lt;strong&gt;@easrng&lt;/strong&gt;&lt;/a&gt; for PR contributions, and additional thanks to &lt;a href=&quot;https://github.com/rawkode&quot;&gt;&lt;strong&gt;@rawkode&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/nz366&quot;&gt;&lt;strong&gt;@nz366&lt;/strong&gt;&lt;/a&gt; for help in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/issues/336&quot;&gt;#366&lt;/a&gt; towards adding &lt;code&gt;deno&lt;/code&gt;!&lt;/p&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Bump object store (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/287&quot;&gt;#287&lt;/a&gt; by &lt;a href=&quot;https://github.com/nz366&quot;&gt;&lt;strong&gt;@nz366&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix CI build for packed aarch64 artifact using x86-64 (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/292&quot;&gt;#292&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Use Brioche nightly for building packed aarch64 build (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/293&quot;&gt;#293&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add new &lt;code&gt;--experimental-lazy&lt;/code&gt; CLI option for &lt;code&gt;brioche build&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/294&quot;&gt;#294&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update Rust version to 1.89 (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/295&quot;&gt;#295&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update clippy lints (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/297&quot;&gt;#297&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix &lt;code&gt;live-update&lt;/code&gt; removing some TypeScript annotations (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/298&quot;&gt;#298&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Resolve all the automatic fixable lints from pedantic (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/299&quot;&gt;#299&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Use lazy lock when it&apos;s possible (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/300&quot;&gt;#300&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Remove features from tokio-util dependency (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/301&quot;&gt;#301&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - July 2025</title><link>https://brioche.dev/blog/project-update-2025-07</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-07</guid><pubDate>Thu, 31 Jul 2025 10:11:48 GMT</pubDate><content:encoded>&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Initial exploration of GUI packages&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jokeyrhyme&quot;&gt;&lt;strong&gt;@jokeyrhyme&lt;/strong&gt;&lt;/a&gt; started &lt;a href=&quot;https://brioche.zulipchat.com/#narrow/channel/440653-general/topic/ninja.20dependency.20unable.20to.20find.20python.20dependency.3F&quot;&gt;a Zulip discussion related to adding GUI packages in Brioche&lt;/a&gt;. That unveiled a bug in the &lt;code&gt;meson&lt;/code&gt; package (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/issues/838&quot;&gt;#838&lt;/a&gt;) which is still blocking more progress. But in the interim, he was still able to add a new package: &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/843&quot;&gt;&lt;code&gt;font_iosevka&lt;/code&gt;&lt;/a&gt;. I see this as an exciting milestone as the first step on the path towards support for GUI packages in Brioche!&lt;/p&gt;
&lt;p&gt;The aforementioned &lt;code&gt;meson&lt;/code&gt; bug is still an annoyance, and there are still a &lt;em&gt;lot&lt;/em&gt; of steps until GUI apps are well-supported in Brioche. If you&apos;re interested in getting involved, feel free to reach out on Zulip, Discord, or open a GitHub Issue or Discussion!&lt;/p&gt;
&lt;h3&gt;Lots of live-update improvements&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; has contributed a ton of improvements and fixes in the &lt;code&gt;brioche-packages&lt;/code&gt; around live-updates in the past month, including suppport for live updates via GitLab, crates.io, NPM, and GitHub tags; more options for automatically matching/sanitizing version numbers; and taking on the work to resolve any issues each week when automatic live-updates fail.&lt;/p&gt;
&lt;p&gt;We have a triple-digit number of packages now, and all the improvements to live-updates has been &lt;em&gt;crucial&lt;/em&gt; to making sure we&apos;re able to stay on top of upstream updates!&lt;/p&gt;
&lt;h3&gt;Infrastructure improvements&lt;/h3&gt;
&lt;p&gt;IRL, &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt; and I were pretty busy this month preparing to host our family over the last week (it went smoothly overall and it was great getting to spend time with them)!&lt;/p&gt;
&lt;p&gt;Before the trip, we wanted to clear out the spare bedroom, where we had our our 22U server rack set up. The noise and heat made the room unlivable (we jokingly called it the sauna).&lt;/p&gt;
&lt;p&gt;We ended up putting a new 42U server rack in the garage and moved our networking equipment there... plus got a new insulated garage door, an AC minisplit in the garage, a new electric subpanel, etc. It ended up being a big project!&lt;/p&gt;
&lt;p&gt;Anyway, I use a mini PC and a Mac mini as GitHub Actions runners for Brioche. We moved those into the garage too, but the new server rack gives a lot more room to grow out to more build machines over time! Basically, we&apos;re future-proofed for lots more self-hosted homelab infrastructure for Brioche.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./project-update-2025-07/server-rack.jpg&quot; alt=&quot;A 42U server rack in the dark. At the top is a UDM Pro and a USW Pro XG 48 PoE switch surrounded by keystone ports. Then a shelf with miscellanea, a shelf with a Mini PC and Mac mini, and a shelf with a Pi-KVM. Near the bottom is a 12-bay TrueNAS Mini R. The photo is brightly illuminated by blinkenlights from the equipment and a violet-tinted glow from an LED light strip embedded in the edge of the rack.&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;🎉 This month, we crossed the 200 package milestone! We&apos;re at 216 total now! 🎉&lt;/p&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;32&lt;/strong&gt; new packages added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;actionlint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;binaryen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_binstall&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_dist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_hack&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_llvm_cov&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_minimal_versions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_no_dev_deps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_quickinstall&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_sort&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_spellcheck&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dagger&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eigen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font_iosevka&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;freetype&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fribidi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gemini_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helix&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iperf3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl_view_allocations&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libunistring&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mpfr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pyrefly&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tinycbor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trunk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vacuum&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wasm_bindgen_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wasm_language_tools&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wasm_pack&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wasm_server_runner&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wasm_tools&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wrangler&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Update Dependabot configuration (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/274&quot;&gt;#274&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Remove unnecessary clone for &lt;code&gt;Brioche.download&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/279&quot;&gt;#279&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - June 2025</title><link>https://brioche.dev/blog/project-update-2025-06</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-06</guid><pubDate>Sun, 29 Jun 2025 06:39:51 GMT</pubDate><content:encoded>&lt;p&gt;In a surprising twist, this month has been all about getting aarch64 support in place!&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;aarch64-linux support&lt;/h3&gt;
&lt;p&gt;Last month, &lt;a href=&quot;https://brioche.dev/blog/project-update-2025-05/#work-on-cross-platform-support&quot;&gt;I wrote about my thoughts on getting aarch64 support in place&lt;/a&gt;. Actually, it was shortly after publishing that Project Update that I started re-thinking things a bit...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The end goal for cross-platform support is still the same as from the May Project Update&lt;/strong&gt;. But I also know it might take a long time to implement everything needed for that! Meanwhile, the more packages we get that are only being built for x86-64 today, the more work it&apos;ll be to add support for aarch64 in the future. So I decided to do a very simple version of cross-platform support now. After all, the end-goal for cross-platform support will require a breaking change (probably), so now&apos;s the right time to get an implementation in place as an MVP.&lt;/p&gt;
&lt;p&gt;The &quot;cross-platform MVP&quot; is very simple: there&apos;s a new &lt;code&gt;std.CURRENT_PLATFORM&lt;/code&gt; const. It has the value &lt;code&gt;&quot;x86_64-linux&quot;&lt;/code&gt; if you&apos;re running on x86-64 Linux, or the value &lt;code&gt;&quot;aarch64-linux&quot;&lt;/code&gt; if you&apos;re running on aarch64 Linux. Pretty straightforward.&lt;/p&gt;
&lt;p&gt;Most packages shouldn&apos;t need to use &lt;code&gt;std.CURRENT_PLATFORM&lt;/code&gt; at all. &lt;code&gt;std.toolchain&lt;/code&gt; and all the compilers / interpreters / etc. were updated to support both platforms, and everything cascades from there and &quot;just works&quot; (usually)!&lt;/p&gt;
&lt;p&gt;The most exciting part though? (🥁 drumroll 🥁)&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;my-12&quot;&amp;gt;
&amp;lt;strong class=&quot;text-3xl block p-4 my-6 text-center border-4 rounded-lg border-gray-300 shadow-xl dark:border-gray-500 dark:shadow-black/80 &quot;&amp;gt;All published packages have now been built for aarch64!&amp;lt;small class=&quot;text-sm align-super&quot;&amp;gt;*&amp;lt;/small&amp;gt;&amp;lt;/strong&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;small class=&quot;text-sm text-gray-400&quot;&amp;gt;*with the exception of the package &amp;lt;code&amp;gt;bugstalker&amp;lt;/code&amp;gt;. &lt;a href=&quot;https://github.com/godzie44/BugStalker&quot;&gt;BugStalker&lt;/a&gt; doesn&apos;t support aarch64 (yet), but it markets itself as a &quot;modern debugger for Linux x86-64&quot;, so fair enough!&amp;lt;/small&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;aarch64 support hasn&apos;t been included in a release yet, but if you install Brioche &lt;a href=&quot;https://github.com/brioche-dev/brioche&quot;&gt;from source&lt;/a&gt; on an aarch64-based Linux machine, all packages can be installed and used from the registry!&lt;/p&gt;
&lt;p&gt;The GitHub Actions workflow in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages&quot;&gt;&lt;code&gt;brioche-packages&lt;/code&gt;&lt;/a&gt; now runs builds for both platforms. x86-64 and aarch64 are treated as equals, so all packages will need to build successfully for both platforms before packages are published (or with a magic comment to skip unsupported packages by platform, like for &lt;code&gt;bugstalker&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;TSDoc for package documentation&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/671&quot;&gt;brioche-packages#671&lt;/a&gt; and &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/675&quot;&gt;brioche-packages#675&lt;/a&gt;, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; went through and updated all the doc comments across all packages to use &lt;a href=&quot;https://tsdoc.org/&quot;&gt;TSDoc&lt;/a&gt; by convention.&lt;/p&gt;
&lt;p&gt;The existing docs were basically Markdown. TSDoc has a ton of support in the TypeScript ecosystem, and it should play much nicer with existing TypeScript tooling. It also unlocks some options down the line, e.g. easily generating static doc pages for published packages.&lt;/p&gt;
&lt;h3&gt;Faster git cloning&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/703&quot;&gt;brioche-packages#703&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; uses the new &lt;code&gt;git clone --revision&lt;/code&gt; option from git v2.49.0 when cloning a specific commit from a repo. GitLab&apos;s coverage of git v2.49.0 &lt;a href=&quot;https://about.gitlab.com/blog/whats-new-in-git-2-49-0/#thin-clone-using---revision&quot;&gt;has a good explainer about the new option&lt;/a&gt;. Not only does this simplify git clones, but it&apos;s faster too! (Check the PR for some benchmark numbers)&lt;/p&gt;
&lt;h3&gt;More live-update updates&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened quite a few PRs to clean up, fix, and improve live updates in the past month. The biggest improvement came in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/717&quot;&gt;brioche-packages#717&lt;/a&gt;, which added a new &lt;code&gt;std.liveUpdateFromNpmPackages&lt;/code&gt; to easily live-update packages based on the version from the NPM registry!&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there are &lt;strong&gt;30&lt;/strong&gt; new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;asdf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blake3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;boost&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_chef&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cyrus_sasl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dependabot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;editline&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gengetopt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gmp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gperf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iamlive&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inframap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;krb5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libevent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libfaketime&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libyaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libzip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lzo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lzop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markdownlint_cli2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ncurses&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nlohmann_json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;patch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;readline&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;renovate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlx_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toml11&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;util_macros&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wabt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yaml_language_server&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Update OpenTelemetry crates (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/257&quot;&gt;#257&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix another &quot;file exists&quot; bug when fetching projects from cache (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/259&quot;&gt;#259&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add JS op to get current platform (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/260&quot;&gt;#260&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Resolve some Clippy pedantic lints (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/263&quot;&gt;#263&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Upgrade all the transient dependencies (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/265&quot;&gt;#265&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update to Rust v1.88 (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/267&quot;&gt;#267&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - May 2025</title><link>https://brioche.dev/blog/project-update-2025-05</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-05</guid><pubDate>Fri, 30 May 2025 08:21:36 GMT</pubDate><content:encoded>&lt;p&gt;This month has been a lot of work on ergonomics, future planning, and &lt;em&gt;a lot&lt;/em&gt; of new packages!&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Simplify recipes in &lt;code&gt;std&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/425&quot;&gt;&lt;code&gt;brioche-packages#425&lt;/code&gt;&lt;/a&gt; updated &lt;code&gt;std&lt;/code&gt; to let you pass a function in most places that expected a recipe, rather than needing to call it first (e.g. passing &lt;code&gt;openssl&lt;/code&gt; instead of &lt;code&gt;openssl()&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as std from &quot;std&quot;;
import meson from &quot;meson&quot;;
import ninja from &quot;ninja&quot;;
import cmake from &quot;cmake&quot;;
import openssl from &quot;openssl&quot;;

export default function (): std.Recipe&amp;lt;std.Directory&amp;gt; {
  // Previous:
  // return std.runBash`...`
  //   .dependencies(std.toolchain(), meson(), ninja(), cmake(), openssl())
  //   .workDir(source)
  //   .toDirectory();

  // New:
  return std.runBash`...`
    .dependencies(std.toolchain, meson, ninja, cmake, openssl)
    .workDir(source)
    .toDirectory();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think this makes Brioche projects look simpler at first glance, and hopefully should be more intuitive too!&lt;/p&gt;
&lt;p&gt;This was enabled by replacing the previous &lt;code&gt;std.AsyncRecipe&lt;/code&gt; type (which could be either &lt;code&gt;Recipe&lt;/code&gt; or &lt;code&gt;Promise&amp;lt;Recipe&amp;gt;&lt;/code&gt;) with the new &lt;code&gt;std.RecipeLike&lt;/code&gt; type (which can be &lt;code&gt;Recipe&lt;/code&gt; or &lt;code&gt;Promise&amp;lt;Recipe&amp;gt;&lt;/code&gt; like before, but also &lt;code&gt;() =&amp;gt; Recipe&lt;/code&gt; or &lt;code&gt;() =&amp;gt; Promise&amp;lt;Recipe&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://brioche.dev/docs/core-concepts/recipes/#stdrecipelike-and-stdrecipe&quot;&gt;the updated docs for more details on &lt;code&gt;RecipeLike&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;pipe&lt;/code&gt; utilities in &lt;code&gt;std&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/424&quot;&gt;&lt;code&gt;brioche-packages#424&lt;/code&gt;&lt;/a&gt; added a new &lt;code&gt;.pipe()&lt;/code&gt; method to recipes, letting you combine together several utilities a little more ergonomically:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default function () {
  // Previous:
  // let recipe = std.runBash`...`
  //   .workDir()
  //   .toDirectory();
  // recipe = std.setEnv(recipe, {
  //   /* env vars */
  // });
  // recipe = std.withRunnableLink(recipe, &quot;bin/path&quot;);
  // return recipe;

  // New:
  return std.runBash`...`
    .workDir()
    .toDirectory()
    .pipe((recipe) =&amp;gt;
      std.setEnv(recipe, {
        /* env vars */
      }),
    )
    .pipe((recipe) =&amp;gt; std.withRunnableLink(recipe, &quot;bin/path&quot;));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found this to be especially helpful when using standalone utility methods like &lt;code&gt;std.withRunnableLink&lt;/code&gt;, etc. Before, you&apos;d have to shuffle between &lt;code&gt;return ...&lt;/code&gt; to &lt;code&gt;const recipe = ...; return ...&lt;/code&gt; to &lt;code&gt;let recipe = ...; return ...&lt;/code&gt;, which could get kinda annoying!&lt;/p&gt;
&lt;p&gt;We&apos;ve adopted this style across the &lt;code&gt;brioche-packages&lt;/code&gt; repo. But for your own projects, the old way still works if &lt;code&gt;.pipe&lt;/code&gt; feels a little too functional for your tastes!&lt;/p&gt;
&lt;p&gt;Oh, and there&apos;s also a standalone &lt;code&gt;std.pipe&lt;/code&gt; function. It&apos;s basically the same, but as a standalone function rather than a method. &lt;a href=&quot;https://brioche.dev/docs/core-concepts/recipes/#stdpipe--recipepipe&quot;&gt;Check the docs for more info about both versions of &lt;code&gt;pipe&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;h3&gt;Work on cross-platform support&lt;/h3&gt;
&lt;p&gt;The next big feature I&apos;m aiming for is cross-platform support in Brioche. Specifically, my goal is to support aarch64 (ARM64) Linux as a build host + target. Since cross-compilation is also an eventual goal, I&apos;m trying to build support in a way that will lead smoothly to cross-compilation too.&lt;/p&gt;
&lt;p&gt;Unfortunately, I think there&apos;s still quite a bit of work remaining before we can get this implemented...&lt;/p&gt;
&lt;h4&gt;Design ideas&lt;/h4&gt;
&lt;p&gt;So, the &quot;big idea&quot; I&apos;m working towards is to support &lt;em&gt;dynamic bindings&lt;/em&gt; in recipes. Basically, you could have a recipe that looks like this (placeholder syntax):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default function curl() {
  return std.runBash`
    # Build OpenSSL from source
    ./configure &amp;amp;&amp;amp; make &amp;amp;&amp;amp; make install
  `
    .workDir(source)
    .dependencies(std.toolchain, openssl)
    .hostPlatform(std.variable(&quot;hostPlatform&quot;))
    .targetPlatform(std.variable(&quot;targetPlatform&quot;));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &quot;trick&quot; is that &lt;code&gt;std.variable&lt;/code&gt; in this case &lt;em&gt;doesn&apos;t&lt;/em&gt; return a string value like &lt;code&gt;linux-x86_64&lt;/code&gt; or whatever. Instead, it returns a &quot;placeholder&quot; value that we can substitute later. If you tried to &lt;code&gt;console.log&lt;/code&gt; them, they would just show as variables named &lt;code&gt;hostPlatform&lt;/code&gt; and &lt;code&gt;targetPlatform&lt;/code&gt;. The Brioche runtime itself would substitute them-- say, based on a CLI option like &lt;code&gt;brioche build --target ...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;...why do we need that? Well, let&apos;s say I want to build curl for x86-64 and aarch64, and create a single tarfile for both of them. I&apos;d like to write this recipe:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default function () {
  // Build curl for x86-64 Linux
  const curlX64 = curl().setVariable({ targetPlatform: &quot;x86_64-linux&quot; });

  // Build curl for aarch64 Linux
  const curlArm = curl().setVariable({ targetPlatform: &quot;aarch64-linux&quot; });

  // Combine into a directory
  const curls = std.directory({
    &quot;curl-x86-64-linux&quot;: curlX64,
    &quot;curl-aarch64-linux&quot;: curlArm,
  });

  // Create a tarfile for the directory
  return createTarfile(curls);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The neat thing is that these &lt;code&gt;hostPlatform&lt;/code&gt; and &lt;code&gt;targetPlatform&lt;/code&gt; values can flow down into dependencies automatically. Since we&apos;re building &lt;code&gt;curl&lt;/code&gt; for both x86-64 and aarch64, that means that &lt;code&gt;openssl&lt;/code&gt; will be built for both as well.&lt;/p&gt;
&lt;p&gt;This isn&apos;t just an arbitrary example either: since OCI / Docker container images are &quot;just&quot; tarfiles, we could use this to easily make multi-platform OCI images with very little extra work!&lt;/p&gt;
&lt;p&gt;There&apos;s a lot of details I&apos;m glossing over, and there&apos;s still even more work to iron out the details for this design, so I&apos;ll leave it at that for now.&lt;/p&gt;
&lt;h4&gt;Roadblocks&lt;/h4&gt;
&lt;p&gt;While starting work to implement and experiment with this design, I&apos;ve basically fallen into a quagmire of issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To maintain backwards compatibility, I think the best option would be to handle these &quot;dynamic bindings&quot; as a &lt;em&gt;preprocessing&lt;/em&gt; step on recipes.&lt;/li&gt;
&lt;li&gt;Brioche has support &quot;proxy recipes&quot; today. A &quot;proxy recipe&quot; is a recipe that contains a hash for another recipe to use in its place. These were added as a performance optimization, since this lets us avoid (de)serializing duplicate recipes in the build graph.&lt;/li&gt;
&lt;li&gt;Because proxy recipes are hashed eagerly, they basically conflict with having a preprocessing step. We also can&apos;t just &quot;turn them off&quot; for a number of reasons.&lt;/li&gt;
&lt;li&gt;...but, I realized we could rely on referential equality in JavaScript as a simpler alternative to proxy recipes. This would be much cleaner and should be faster too.&lt;/li&gt;
&lt;li&gt;...but that would require our own way to deserialize values from JavaScript to Rust, due to limitations with how we currently deserialize. But the &lt;code&gt;Recipe&lt;/code&gt; type is huge and complex, and it&apos;d be unwieldy to hand-write deserialization logic.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For (4), I&apos;ve already got some prototype code that handles this properly on the JS side. For (5), I&apos;ve been playing around with &lt;a href=&quot;https://facet.rs/&quot;&gt;facet&lt;/a&gt; recently. Right now, I believe it&apos;s the best path forward for handling deserialization on the Rust side, which in turn should start to unravel these issues.&lt;/p&gt;
&lt;p&gt;And just to be clear, cross-platform support is the catalyst for cleaning this up, but I think getting this cleaned up anyway will be a good change overall, even ignoring cross-platform support.&lt;/p&gt;
&lt;h4&gt;Breaking changes?&lt;/h4&gt;
&lt;p&gt;But, I&apos;m also unsure if untangling the whole mess above can be done in a backwards-compatible way. Well, not so much if it &lt;em&gt;can&lt;/em&gt; be done, but rather if it&apos;d be better to do so as a breaking change...&lt;/p&gt;
&lt;p&gt;I secretly hoped Brioche would graduate from v0.1.x straight to v1.0.0, but I&apos;ve already got a wishlist of minor breaking changes I&apos;d love to make to the data model. It might be time to rip the band-aid.&lt;/p&gt;
&lt;p&gt;I&apos;m still on the fence overall, but I&apos;m leaning more towards it. That means cross-platform support might need to wait until Brioche v0.2.0.&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;64&lt;/strong&gt; new packages!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bash_language_server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;biome&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brotli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bubblewrap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bugstalker&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_about&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_audit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_bloat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_msrv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_mutants&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_nextest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo_udeps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cmctl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;codex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cosign&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delve&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;difftastic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eks_node_viewer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;go_mockery&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;golangci_lint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gosec&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grcov&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gron&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gtest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;htop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hyperfine&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jjui&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lerc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libcap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libdeflate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libgit2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libjpeg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libjpeg_turbo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libpng&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libsodium&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libssh2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libunwind&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markdownlint_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mdbook&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;meson&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mitmproxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ninja&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pcre&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pnpm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rip2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sccache&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;snazy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;starship&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tailspin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tflint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trivy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uthash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vegeta&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xcaddy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yazi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zlib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zlib_ng&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zziplib&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;, who added a majority of these packages!&lt;/p&gt;
&lt;p&gt;(the list in this section is so long now...! I feel like I&apos;ll need to eventually tweak the CSS a bit so it doesn&apos;t take up so much space on the page!)&lt;/p&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;live-update&lt;/code&gt; subcommand to use &lt;code&gt;liveUpdate&lt;/code&gt; export (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/237&quot;&gt;#237&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Speed up debug compilation (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/238&quot;&gt;#238&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Remove use of legacy registry endpoints (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/239&quot;&gt;#239&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix &lt;code&gt;brioche live-update&lt;/code&gt; not showing output on error (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/243&quot;&gt;#243&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update Rust version to 1.87 (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/248&quot;&gt;#248&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Upgrade Rust version for Brioche-in-Brioche (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/249&quot;&gt;#249&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add workaround for &quot;file exists&quot; bug in CI (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/250&quot;&gt;#250&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update CI macOS default images (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/251&quot;&gt;#251&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;ci: Add GitHub Actions updates through dependabot (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/252&quot;&gt;#252&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - April 2025</title><link>https://brioche.dev/blog/project-update-2025-04</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-04</guid><pubDate>Sun, 27 Apr 2025 01:48:00 GMT</pubDate><content:encoded>&lt;p&gt;The biggest news this month was &lt;a href=&quot;/blog/announcing-brioche-v0-1-5/&quot;&gt;the release of Brioche v0.1.5&lt;/a&gt;! There were also 2 PSAs to be aware of from that announcement: &lt;strong&gt;registry support for Brioche v0.1.4 and earlier will be ending on 2025-04-30&lt;/strong&gt;, and &lt;strong&gt;upgrading to Brioche v0.1.5 affects self-hosted registries pretty drastically&lt;/strong&gt;, check the release announcement for more details.&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Brioche v0.1.5 features&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;/blog/announcing-brioche-v0-1-5/&quot;&gt;Brioche v0.1.5 announcement&lt;/a&gt; includes all the details for the new release, so go check that out for more! Since the last project update, there were a few smaller changes that got merged prior to the release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Support inheriting host CA certificates&lt;/strong&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/232&quot;&gt;#232&lt;/a&gt;). This adds a new special process template value that allows passing in the host&apos;s CA certificates into a recipe, but only when &lt;code&gt;unsafe.networking&lt;/code&gt; is enabled! Once the supporting changes land in &lt;code&gt;std&lt;/code&gt;, this means the &lt;code&gt;ca_certificates&lt;/code&gt; package won&apos;t be needed for making HTTPS requests in most cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement &lt;code&gt;currentDir&lt;/code&gt; option when baking process recipes&lt;/strong&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/231&quot;&gt;#231&lt;/a&gt;). This allows for changing which directory a process recipe starts in, rather than needing to use &lt;code&gt;cd&lt;/code&gt; within a shell script&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement the &lt;code&gt;unsandboxed&lt;/code&gt; sandbox backend&lt;/strong&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/230&quot;&gt;#230&lt;/a&gt;). This is a very simple backend that can work as a &quot;last resort&quot; when other sandboxing wouldn&apos;t work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Update custom cache to work as a layer with default cache&lt;/strong&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/229&quot;&gt;#229&lt;/a&gt;). The new cache was &lt;a href=&quot;https://brioche.dev/blog/project-update-2025-02/#major-overhaul-and-speedup-for-cached-builds&quot;&gt;merged in February&lt;/a&gt;. When it was first merged, setting a custom cache would &lt;em&gt;replace&lt;/em&gt; the default cache, which made it hard to use a custom cache in practice! Now it works as a layer on top of the default cache, which I made sure to get in before the v0.1.5 release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show download sizes in console&lt;/strong&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/227&quot;&gt;#227&lt;/a&gt;). Previously, the console would show the &quot;blob count&quot; when fetching from the cache, the &quot;blob + recipe&quot; count when fetching from the legacy registry, and would just show a percentage for downloads and archives. Now, it will consistently show a message with the current bytes and the total bytes (where possible). I found this to help give some context for large / slow downloads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fix V8 platform initialization&lt;/strong&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/225&quot;&gt;#225&lt;/a&gt;). I switched to daily driving Linux recently (from Windows + WSL) and ran into a weird crash in V8 when running Brioche tests. I dug in and found that it had to do with how the V8 platform got set up depending on your CPU flags. Fixing it was kinda dirty, but running test works for me again!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Merge various security fixes&lt;/strong&gt; (various Dependabot PRs). There were several outstanding Dependabot alerts in Brioche, which have all been resolved. Most were in the &lt;code&gt;runtime&lt;/code&gt; NPM project which has no security impact on Brioche due to the nature of how restricted our runtime is (I believe). But there was one fix that was relevant: an update to the &lt;code&gt;zip&lt;/code&gt; dependency to resolve &lt;a href=&quot;https://github.com/advisories/GHSA-94vh-gphv-8pm8&quot;&gt;CVE-2025-29787&lt;/a&gt;. Support for unarchiving zip files was merged &lt;a href=&quot;/blog/project-update-2025-02/#support-for-unarchiving-zip-files&quot;&gt;last month&lt;/a&gt;, but this feature only landed in v0.1.5, so there were no vulnerable versions of Brioche released!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Dropping support for earlier versions of Brioche&lt;/h3&gt;
&lt;p&gt;As mentioned in the v0.1.5 announcement, &lt;a href=&quot;/blog/announcing-brioche-v0-1-5/#psa-sunsetting-support-for-older-versions-of-brioche&quot;&gt;I&apos;ll be removing APIs used by older versions of Brioche from the registry after 2025-04-30&lt;/a&gt;, effectively ending support for Brioche versions &amp;lt;=v0.1.4.&lt;/p&gt;
&lt;p&gt;Some packages in the &lt;code&gt;brioche-packages&lt;/code&gt; repo have already started adopting cyclic dependencies, which already can&apos;t be fetched from the registry for prior versions. We&apos;ve also started adding some features to &lt;code&gt;std&lt;/code&gt; that depend on v0.1.5 features, so earlier versions of Brioche are already starting to lose out on the latest changes.&lt;/p&gt;
&lt;h3&gt;Package live updates&lt;/h3&gt;
&lt;p&gt;I merged &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/234&quot;&gt;#234&lt;/a&gt; recently, which added the new &lt;code&gt;brioche live-update&lt;/code&gt; subcommand. This new command allows us to define a special export per package, which allows packages to update themselves based on the latest upstream version. Thanks to the work of &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;, 71 out of 90 packages already support live-updates, which will massively help with keeping packages up to date!&lt;/p&gt;
&lt;p&gt;The name was based on Homebrew&apos;s &lt;a href=&quot;https://docs.brew.sh/Brew-Livecheck&quot;&gt;&lt;code&gt;livecheck&lt;/code&gt;&lt;/a&gt; subcommand. Originally, I was going to call it &lt;code&gt;auto-update&lt;/code&gt; and so we&apos;ve been using the name &lt;code&gt;autoUpdate&lt;/code&gt; as the export, but I&apos;m happier with the term &quot;live update&quot;. The next step will be to rename all of the &lt;code&gt;autoUpdate&lt;/code&gt; exports to &lt;code&gt;liveUpdate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;ve also gotten a first-pass GitHub Action set up to create PRs from the live updates, many of which &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pulls?q=is%3Apr+label%3A%22live+update%22+created%3A%3C%3D2025-04-26&quot;&gt;have started getting merged in &lt;code&gt;brioche-packages&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;brioche.dev&lt;/code&gt; updates&lt;/h3&gt;
&lt;p&gt;The source for &lt;a href=&quot;https://brioche.dev&quot;&gt;https://brioche.dev&lt;/a&gt; is itself &lt;a href=&quot;https://github.com/brioche-dev/brioche.dev&quot;&gt;in a public repo&lt;/a&gt;, which includes automatic updates through Dependabot. Last week, I saw an exciting update come in that added support for using Tailwind v4 with Starlight!&lt;/p&gt;
&lt;p&gt;...that update required &lt;em&gt;a lot&lt;/em&gt; of fixes to get the site looking right again. But, I spent a lot of time fixing stuff, and merged the update. One really nice outcome is that the blog posts now use the same Markdown stylings as the doc pages, including header links. Nice!&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;4&lt;/strong&gt; new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubent&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/308&quot;&gt;#308&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;popeye&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/300&quot;&gt;#300&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rclone&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/322&quot;&gt;#322&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;strace&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/272&quot;&gt;#272&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Fix Deno Core / V8 platform initialization (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/225&quot;&gt;#225&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Upgrade dependencies in &lt;code&gt;runtime&lt;/code&gt; NPM project (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/226&quot;&gt;#226&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update console output to show download / archive sizes (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/227&quot;&gt;#227&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update Rust to v1.86 (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/228&quot;&gt;#228&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update custom cache to work as a layer with default cache (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/229&quot;&gt;#229&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Implement the &lt;code&gt;unsandboxed&lt;/code&gt; sandbox backend (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/230&quot;&gt;#230&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Implement &lt;code&gt;currentDir&lt;/code&gt; option when baking process recipes (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/231&quot;&gt;#231&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Support inheriting host CA certificates (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/232&quot;&gt;#232&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;brioche live-update&lt;/code&gt; command to live-update/auto-update projects (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/234&quot;&gt;#234&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;std updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Add support for &lt;code&gt;zip&lt;/code&gt; archive format (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/335&quot;&gt;#335&lt;/a&gt; by &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Announcing Brioche v0.1.5</title><link>https://brioche.dev/blog/announcing-brioche-v0-1-5</link><guid isPermaLink="true">https://brioche.dev/blog/announcing-brioche-v0-1-5</guid><pubDate>Sun, 20 Apr 2025 06:20:05 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://brioche.dev/&quot;&gt;Brioche&lt;/a&gt; is a new package manager and build tool that makes it easy to mix and match languages and tools for your own development projects. Check &lt;a href=&quot;/docs/installation/&quot;&gt;the installation docs&lt;/a&gt; to get started or run &lt;code&gt;brioche self-update&lt;/code&gt; to update Brioche!&lt;/p&gt;
&lt;p&gt;Since the &lt;a href=&quot;/blog/announcing-brioche-v0-1-4&quot;&gt;release of v0.1.4&lt;/a&gt;, we&apos;ve gathered a number of new features and quality of life improvements! Check the &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.5&quot;&gt;release notes&lt;/a&gt; for all the changes for this release, and thanks to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/paricbat&quot;&gt;&lt;strong&gt;@paricbat&lt;/strong&gt;&lt;/a&gt;, and &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt; for PR contributions for this release!&lt;/p&gt;
&lt;p&gt;Before diving into the features, 2 quick PSAs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Support for earlier versions of Brioche will phase out soon&lt;/strong&gt;, so upgrading is strongly recommended. TL;DR: the registry will no longer support Brioche &amp;lt;=v0.1.4 as of 2025-04-30. &lt;a href=&quot;#psa-sunsetting-support-for-older-versions-of-brioche&quot;&gt;See below for more details&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted registries behave very differently now&lt;/strong&gt;. If you&apos;re using a self-hosted registry, you&apos;ll need to update your configration and migrate your data after upgrading. &lt;a href=&quot;#psa-self-hosted-registry-changes&quot;&gt;See below for more details&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;New cache&lt;/h2&gt;
&lt;p&gt;The biggest quality-of-life improvement day-to-day is the new cache system. Fetching large artifacts should now be much faster, and it&apos;s much easier to set up a self-hosted or private cache!&lt;/p&gt;
&lt;p&gt;Since the initial release, Brioche has used a fairly naive means for storing and loading cached values: each individual file would be stored and fetched independently (although they were at least compressed and deduplicated by hash). That meant that fetching large directories with lots of small files would be painfully slow.&lt;/p&gt;
&lt;p&gt;Now, artifacts are stored in the cache as a custom archive format. Plus, to reduce costs, archives are deduplicated using a &lt;a href=&quot;https://joshleeb.com/posts/content-defined-chunking.html&quot;&gt;content-defined chunking&lt;/a&gt; algorithm to avoid storing data redundantly.&lt;/p&gt;
&lt;p&gt;But the best part? There are multiple supported backends for caching, so &lt;strong&gt;setting up a custom cache is very easy!&lt;/strong&gt; Any S3-compatible storage provider should work with the custom cache, and it only takes a single env var to opt-in to the custom cache, which is much easier to use for CI/CD workflows. &lt;a href=&quot;/docs/core-concepts/cache&quot;&gt;Check the docs for more details on caching&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Debug shell for failed build&lt;/h2&gt;
&lt;p&gt;Today, we have the &lt;code&gt;brioche jobs logs&lt;/code&gt; subcommand to show all the output from a failed build. It&apos;s an indespenable tool for diagnosing build errors, especially when working on new packages. It&apos;s very useful! But sometimes though, I just wish I could &lt;em&gt;reach into&lt;/em&gt; a build and poke around with it-- explore files, re-run commands with different parameters, etc.&lt;/p&gt;
&lt;p&gt;The new &lt;code&gt;brioche jobs debug-shell&lt;/code&gt; command lets you do just that. When a build fails, you can run &lt;code&gt;brioche jobs debug-shell ${path_to_events_file}&lt;/code&gt;, and you&apos;ll get dropped right into an interactive shell, right from where the build failed! It&apos;ll run with the exact same sandbox semantics as the build did too.&lt;/p&gt;
&lt;p&gt;Here&apos;s a quick recording to demo what this is like in practice:&lt;/p&gt;
&lt;p&gt;&amp;lt;script src=&quot;https://asciinema.org/a/d7DsWq9zVEC0LtjhsY2Ciyu39.js&quot; id=&quot;asciicast-d7DsWq9zVEC0LtjhsY2Ciyu39&quot; async=&quot;true&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h2&gt;Support projects with cyclic imports&lt;/h2&gt;
&lt;p&gt;This one was originally motivated by a long-standing draft PR in the &lt;code&gt;brioche-packages&lt;/code&gt; repo: &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/228&quot;&gt;#228&lt;/a&gt;. Basically, this PR was blocked because there was a cyclic dependency between two projects: we wanted the &lt;code&gt;curl&lt;/code&gt; package to use the &lt;code&gt;libpsl&lt;/code&gt; package, but a helper function from &lt;code&gt;libpsl&lt;/code&gt; dependends on &lt;code&gt;curl&lt;/code&gt; (transitively).&lt;/p&gt;
&lt;p&gt;In Brioche&apos;s JavaScript runtime (Deno Core / V8), this works without any hiccups. But for Brioche itself, I needed to make some adjustments to how projects were represented internally. It turned out to be a lot of work, but it works seamlessly now!&lt;/p&gt;
&lt;h2&gt;New &lt;code&gt;unsandboxed&lt;/code&gt; sandbox backend&lt;/h2&gt;
&lt;p&gt;There might be times where the &lt;code&gt;linux_namespace&lt;/code&gt; sandbox backend can&apos;t be used for builds or might be limited due to security policies.&lt;/p&gt;
&lt;p&gt;So, I implemented the &lt;code&gt;unsandboxed&lt;/code&gt; sandbox backend. As the name implies, it &lt;em&gt;disables&lt;/em&gt; sandboxing. Generally, this isn&apos;t what you want, so &lt;strong&gt;this should only be used if you have no other options or if you know what you&apos;re doing!&lt;/strong&gt; &lt;a href=&quot;/docs/configuration#unsandboxed&quot;&gt;Check the docs&lt;/a&gt; for caveats and details on enabling this backend.&lt;/p&gt;
&lt;p&gt;The coolest part though is that this sandbox only relies on Rust &lt;code&gt;std&lt;/code&gt;, so it should work on &lt;em&gt;any&lt;/em&gt; platform! This isn&apos;t very useful in general, but I think this will come in handy when standing up Brioche on new platforms.&lt;/p&gt;
&lt;h2&gt;Coming soon to &lt;code&gt;std&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Brioche itself includes several new features that will be used by the &lt;code&gt;std&lt;/code&gt; package. These will be published sometime after release, and you&apos;ll need to update to the latest version of the &lt;code&gt;std&lt;/code&gt; package to use them-- keep an eye on the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/main/packages/std/CHANGELOG.md&quot;&gt;&lt;code&gt;std&lt;/code&gt; changelog&lt;/a&gt; for when they land!&lt;/p&gt;
&lt;h3&gt;Support for unarchiving &lt;code&gt;.zip&lt;/code&gt; files&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paricbat&quot;&gt;&lt;strong&gt;@paricbat&lt;/strong&gt;&lt;/a&gt; implemented support for unarchiving zip files, so they can now be treated as first-class citizens just like &lt;code&gt;.tar&lt;/code&gt; files!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Brioche.download(
  &quot;https://github.com/brioche-dev/brioche/archive/refs/tags/v0.1.4.zip&quot;,
).unarchive(&quot;zip&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;process.currentDir&lt;/code&gt; to change a process&apos;s starting directory&lt;/h3&gt;
&lt;p&gt;By default, processes start in an empty directory called &lt;code&gt;work&lt;/code&gt;. You can pre-populate this directory using the &lt;code&gt;.workDir()&lt;/code&gt; method, but this just writes files into this &lt;code&gt;work&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Sometimes, it&apos;s useful to start in a different directory directly. Most commonly, it can be useful to start in &lt;code&gt;$BRIOCHE_OUTPUT&lt;/code&gt;, which can be used to create or modify an artifact through a shell script.&lt;/p&gt;
&lt;p&gt;Previously, you&apos;d need to start your shell script with &lt;code&gt;cd &quot;$BRIOCHE_OUTPUT&quot;&lt;/code&gt;, but soon you&apos;ll be able to use &lt;code&gt;.currentDir()&lt;/code&gt; to set the starting directory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Apply a sed script to each `.pc` file within `${recipe}/lib/pkgconfig`
recipe = std.runBash`
  sed -i &apos;s|=/|=\${pcfiledir}/../../|&apos; lib/pkgconfig/*.pc
`
  .outputScaffold(recipe)
  .currentDir(std.outputPath);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;Brioche.gitCheckout&lt;/code&gt; to checkout a repo directly&lt;/h3&gt;
&lt;p&gt;Today, if you want to check out a git repo without specifying a commit hash directly, the easiest way is by combining the &lt;a href=&quot;/docs/core-concepts/statics/#briochegitref&quot;&gt;&lt;code&gt;Brioche.gitRef&lt;/code&gt; static&lt;/a&gt; with &lt;code&gt;git.gitCheckout&lt;/code&gt;, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as std from &quot;std&quot;;
import { gitCheckout } from &quot;git&quot;;

const source = gitCheckout(
  Brioche.gitRef({
    repository: &quot;https://github.com/brioche-dev/brioche.git&quot;,
    ref: &quot;main&quot;,
  }),
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Brioche.gitCheckout&lt;/code&gt; is a new static, which combines both functions together:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as std from &quot;std&quot;;
import &quot;git&quot;;

const source = Brioche.gitCheckout({
  repository: &quot;https://github.com/brioche-dev/brioche.git&quot;,
  ref: &quot;main&quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;PSA: Sunsetting support for older versions of Brioche&lt;/h2&gt;
&lt;p&gt;Projects with &lt;a href=&quot;#support-projects-with-cyclic-imports&quot;&gt;cyclic imports&lt;/a&gt; are represented very differently from projects &lt;em&gt;without&lt;/em&gt; cyclic imports. As such, projects with cyclic imports won&apos;t work on earlier versions of Brioche.&lt;/p&gt;
&lt;p&gt;On top of that, the &lt;a href=&quot;#new-cache&quot;&gt;new cache&lt;/a&gt; stores data independently from how the registry cached data previously. As of the Brioche v0.1.5 release, I&apos;m paying costs for both the &quot;legacy&quot; storage as well as the new cache storage.&lt;/p&gt;
&lt;p&gt;For both of these reasons, I&apos;m planning on sunsetting support for prior versions of Brioche. &lt;strong&gt;On 2025-04-30 (or later), registry requests will fail for Brioche &amp;lt;=v0.1.4&lt;/strong&gt;. The registry will no longer serve the endpoints used by prior versions of Brioche.&lt;/p&gt;
&lt;p&gt;Existing data from the registry has already been migrated to the new cache, so this should be seamless when upgrading to Brioche v0.1.5 when using the official registry/cache. But I wanted to give a grace period before sunsetting prior versions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you have questions/comments/concerns about this timeline, please reach out via Discord, Zulip, or GitHub!&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;PSA: Self-hosted registry changes&lt;/h2&gt;
&lt;p&gt;With the &lt;a href=&quot;#new-cache&quot;&gt;new cache&lt;/a&gt;, project files are now stored and retrieved via the cache instead of via the registry. However, the registry is still used to associate project names with the artifact hash stored in the cache.&lt;/p&gt;
&lt;p&gt;If you&apos;re using Brioche &amp;lt;=v0.1.4 with a self-hosted registry, this means a few things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You&apos;ll need to update your config to use a custom cache along with a self-hosted registry, in order to store project files.&lt;/li&gt;
&lt;li&gt;Since recipes/bakes/artifacts are no longer stored in the registry, you&apos;ll need to either start from a clean slate or migrate to the cache.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you&apos;re using a self-hosted registry today and need help migrating to Brioche v0.1.5, please reach out via Discord, Zulip, or GitHub. This release includes some internal commands / options that can help with the migration, but these will likely be removed before the next release!&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - March 2025</title><link>https://brioche.dev/blog/project-update-2025-03</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-03</guid><pubDate>Mon, 31 Mar 2025 07:35:49 GMT</pubDate><content:encoded>&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Cyclic imports&lt;/h3&gt;
&lt;p&gt;Last month, I &lt;a href=&quot;/blog/project-update-2025-02#recursive-import-troubles&quot;&gt;mentioned challenges with a package where we wanted cyclic/recursive imports&lt;/a&gt;. Well, I&apos;m happy to report that that PR &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/211&quot;&gt;#211&lt;/a&gt; added support for cyclic imports and has been merged in! It allows two projects to import each other as long as they&apos;re part of the same &lt;a href=&quot;https://brioche.dev/docs/core-concepts/workspaces/&quot;&gt;workspace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Getting this feature over the finish line took a lot more work than I was expecting! To get into the weeds a bit: Brioche internally represented projects as a JSON structure that looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  // Value of `export const project`
  &quot;definition&quot;: {
    &quot;name&quot;: &quot;curl&quot;,
    &quot;version&quot;: &quot;8.11.1&quot;
  },

  // Hashes of the TypeScript modules from the project
  &quot;modules&quot;: {
    /* ... */
  },

  // Any statics (downloads, etc) from the project
  &quot;statics&quot;: {
    /* ... */
  },

  // Other projects imported by this project
  &quot;dependencies&quot;: {
    &quot;std&quot;: &quot;&amp;lt;hash&amp;gt;&quot;,
    &quot;openssl&quot;: &quot;&amp;lt;hash&amp;gt;&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This JSON structure is then normalized and hashed, which is used as the &lt;code&gt;ProjectHash&lt;/code&gt;, which is used to uniquely identify the project. This hash is used for publishing and retrieving the projects via the registry, and is used in lockfiles when another project references it. Each value under &lt;code&gt;dependencies&lt;/code&gt; is a &lt;code&gt;ProjectHash&lt;/code&gt; value... which means that a &lt;code&gt;ProjectHash&lt;/code&gt; depends on the &lt;code&gt;ProjectHash&lt;/code&gt; values of its dependencies.&lt;/p&gt;
&lt;p&gt;...do you see the problem? If &lt;code&gt;fizz&lt;/code&gt; and &lt;code&gt;buzz&lt;/code&gt; depend on each other, then &lt;code&gt;fizz&lt;/code&gt; depends on the hash of &lt;code&gt;buzz&lt;/code&gt;, and &lt;code&gt;buzz&lt;/code&gt; depends on the hash of &lt;code&gt;fizz&lt;/code&gt;, which... uh... you can&apos;t do!&lt;/p&gt;
&lt;p&gt;To handle cycles, I introduced some indirection: projects get grouped into a &quot;workspace&quot;, which basically just contains multiple of the JSON value from before:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;packages/curl&quot;: {
    // Value of `export const project`
    &quot;definition&quot;: {
      &quot;name&quot;: &quot;curl&quot;,
      &quot;version&quot;: &quot;8.11.1&quot;
    }

    // ... same fields as before ...
  },
  &quot;packages/openssl&quot;: {
    // ...
  },
  &quot;packages/std&quot;: {
    // ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We hash &lt;em&gt;this&lt;/em&gt; JSON value to get a &lt;code&gt;WorkspaceHash&lt;/code&gt;. We still have a &lt;code&gt;ProjectHash&lt;/code&gt;, but it instead comes from a JSON value that references the &lt;code&gt;WorkspaceHash&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;type&quot;: &quot;workspace_member&quot;,
  &quot;workspace&quot;: &quot;&amp;lt;hash&amp;gt;&quot;,
  &quot;path&quot;: &quot;packages/curl&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, as long as &quot;&lt;em&gt;workspaces&lt;/em&gt;&quot; don&apos;t form cycles, we&apos;re golden.&lt;/p&gt;
&lt;p&gt;I&apos;ve also been using quotes around &quot;workspaces&quot;. We do only group projects together when they&apos;re part of the same &lt;a href=&quot;https://brioche.dev/docs/core-concepts/workspaces/&quot;&gt;workspace&lt;/a&gt; on disk, i.e. they&apos;re under a directory containing a &lt;code&gt;brioche_workspace.toml&lt;/code&gt; file. But, we only group projects together in a shared structure if we need to break a cycle: we build a graph of projects with their dependencies, and build a &quot;workspace&quot; from each &lt;a href=&quot;https://en.wikipedia.org/wiki/Strongly_connected_component&quot;&gt;strongly-connected component&lt;/a&gt; of the graph containing more than one project (and we validate that each grouped project contains the same &lt;code&gt;brioche_workspace.toml&lt;/code&gt; file). This both ensures hash stability (since the hash only depends on the subset of projects part of the same workspace group) &lt;em&gt;and&lt;/em&gt; backwards compatibility (if a project doesn&apos;t have any cycles, it still uses the &quot;original&quot; JSON format and so will keep the same hash as before, which is important for prior versions of Brioche).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Side note&lt;/strong&gt;: I haven&apos;t been super happy with calling these grouped projects &quot;workspaces&quot; in this context, so I might switch to a different term before this feature gets shipped.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Debug shell for failed jobs&lt;/h3&gt;
&lt;p&gt;Okay, this one isn&apos;t super flashy, but it&apos;s something I&apos;ve wanted for a long time and I&apos;m really happy I finally had a chance to sit down and implement it! It landed in PR &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/215&quot;&gt;#215&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;TL;DR: if a build fails, you can now run &lt;code&gt;brioche jobs debug-shell $path_to_event_file&lt;/code&gt; and you&apos;ll get dropped into a shell in the sandbox for the failed build! It doesn&apos;t sound super exciting, but it can be a huge quality-of-life boost when trying to write a package with a slow build process.&lt;/p&gt;
&lt;p&gt;The catalyst was LLVM, which I worked on packaging last week. The build failed consistently at &lt;em&gt;98%&lt;/em&gt;, after about an hour and a half and after consuming around 150 GB of disk space! Even worse: I tried running the build through &lt;code&gt;strace&lt;/code&gt; to log all the subprocesses started by the build-- an invaluable tool for finding subtle build issues previously-- and something else went wrong earlier in the build process. My go-to debugging tool was interefering in some way with the build.&lt;/p&gt;
&lt;p&gt;After I added the &lt;code&gt;brioche jobs debug-shell&lt;/code&gt;, I could jump right into the LLVM build process. Since almost the whole build had already finished, running &lt;code&gt;cmake build&lt;/code&gt; within the shell let me explore what went wrong-- basically doing an autopsy on the build itself. Along with &lt;code&gt;strace&lt;/code&gt;, I was able to narrow down what went wrong with the build, short-circuiting the rest of the build that ran without problems.&lt;/p&gt;
&lt;p&gt;The failure turned out to be from &lt;code&gt;brioche-ld&lt;/code&gt;. I never implemented support for &lt;code&gt;@file&lt;/code&gt;-style arguments, which was causing the build to fail. I got a fix ready pretty quickly in &lt;a href=&quot;https://github.com/brioche-dev/brioche-runtime-utils/pull/21&quot;&gt;brioche-dev/brioche-runtime-utils#21&lt;/a&gt;. It would&apos;ve taken &lt;em&gt;much&lt;/em&gt; longer to track this down without the new debug shell command!&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;Brioche.gitCheckout&lt;/code&gt; groundwork&lt;/h3&gt;
&lt;p&gt;Currently, if you want to check out a git repo in Brioche, the recommended way is to combine the &lt;code&gt;gitCheckout&lt;/code&gt; and &lt;code&gt;Brioche.gitRef&lt;/code&gt; functions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const source = gitCheckout(
  Brioche.gitRef({
    repository: &quot;https://github.com/antonmedv/fx.git&quot;,
    ref: &quot;35.0.0&quot;,
  }),
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After some discussion about standardizing and improving how downloads from GitHub are handled in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/discussions/176&quot;&gt;brioche-dev/brioche-packages#176&lt;/a&gt;, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; proposed having a single function to combine both steps.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Brioche.gitRef&lt;/code&gt; is a &lt;a href=&quot;https://brioche.dev/docs/core-concepts/statics/#briochegitref&quot;&gt;static&lt;/a&gt;, which means that it gets some super-powers from the runtime so it can push stuff into the lockfile. However, that also comes with some tight restrictions: it &lt;em&gt;must&lt;/em&gt; be called with very simple arguments, or it&apos;ll return a runtime error. That also means that it can&apos;t just be wrapped in another function call.&lt;/p&gt;
&lt;p&gt;So, to solve this, I added &lt;code&gt;Brioche.gitCheckout&lt;/code&gt; as a new static in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/218&quot;&gt;#218&lt;/a&gt;. The runtime itself treats it identically to &lt;code&gt;Brioche.gitRef&lt;/code&gt; when it comes to the lockfile, but the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/&quot;&gt;&lt;code&gt;brioche-packages&lt;/code&gt;&lt;/a&gt; repo can take care of the implementation so that it gets the commit and checks it out from the repo in one function call.&lt;/p&gt;
&lt;p&gt;The implementation still hasn&apos;t landed yet, but expect to see it shortly after the next Brioche release!&lt;/p&gt;
&lt;h3&gt;New build machine&lt;/h3&gt;
&lt;p&gt;Whenever a build is triggered for &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/&quot;&gt;&lt;code&gt;brioche-packages&lt;/code&gt;&lt;/a&gt;, it runs on a server in my and &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;&apos;s homelab. Unfortunately, this hasn&apos;t been a great setup for a number of reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The server it runs on is used for other stuff too. Sharing CPU with the other stuff makes builds slower overall&lt;/li&gt;
&lt;li&gt;The I/O on the server is really slow-- it&apos;s fine for low-usage stuff, but it does noticeably impact build times&lt;/li&gt;
&lt;li&gt;There&apos;s some kind of issue in the kernel or firmware or something that causes disks to permanently disconnect until a reboot. It only happens about once a month, and seems to trigger more often with high I/O usage. Not a blocker, but it&apos;s definitely been annoying to deal with!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I finally decided to bite the bullet and ordered a new mini PC recently. I went for the Minisforum MS-A1, and it&apos;s now set up to run all the build jobs in the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/&quot;&gt;&lt;code&gt;brioche-packages&lt;/code&gt;&lt;/a&gt; repo! Builds have been noticeably faster&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;10&lt;/strong&gt; new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;re2c&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/241&quot;&gt;#241&lt;/a&gt; by &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;process_compose&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/257&quot;&gt;#257&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;icu&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/258&quot;&gt;#258&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;postgresql&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/259&quot;&gt;#259&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libtirpc&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/264&quot;&gt;#264&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rpcsvc_proto&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/265&quot;&gt;#265&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;php&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/266&quot;&gt;#266&lt;/a&gt; by &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;caddy&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/269&quot;&gt;#269&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/270&quot;&gt;#270&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llvm&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/271&quot;&gt;#271&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Fix occasional error when an inline cache archive contains an empty blob (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/196&quot;&gt;#196&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Rust 1.85 support (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/197&quot;&gt;#197&lt;/a&gt; by &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Handle projects with cyclic (circular) dependencies (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/211&quot;&gt;#211&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add a new command to start a debug shell within a job (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/215&quot;&gt;#215&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix &quot;File exists&quot; error when fetching a project from the cache (sometimes) (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/216&quot;&gt;#216&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add support for &lt;code&gt;Brioche.gitCheckout&lt;/code&gt; as a static (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/218&quot;&gt;#218&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - February 2025</title><link>https://brioche.dev/blog/project-update-2025-02</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-02</guid><pubDate>Wed, 26 Feb 2025 08:41:51 GMT</pubDate><content:encoded>&lt;p&gt;Some highlights this month have been a major overhaul to build caching and more progress towards automatic updates!&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Major overhaul (and speedup) for cached builds&lt;/h3&gt;
&lt;p&gt;Last month, I &lt;a href=&quot;/blog/project-update-2025-01#sync-speedup&quot;&gt;talked about progress on speeding up synced builds&lt;/a&gt;, which I still felt was a big win, but it involved some manual work at the packaging level. I wanted to come up with a way to improve syncing across the board &lt;em&gt;without&lt;/em&gt; any extra manual work... which led to &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/179&quot;&gt;#179&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The problem is that even moderately complicated directory structures would take a &lt;em&gt;long&lt;/em&gt; time to fetch from the registry-- each file &lt;em&gt;and&lt;/em&gt; each subdirectory required a separate request. Things were downloaded in parallel to make this somewhat tolerable, but the sheer number of requests made fetching from the registry pretty slow.&lt;/p&gt;
&lt;p&gt;Now, the new cache stores each artifact as a custom archive format. For small artifacts, that&apos;s basically it: fetch the entire archive, unpack it, and you&apos;re done. But, once the total data in the archive crosses some threshold (2 MB currently), we break the archive up into chunks using a &lt;a href=&quot;https://joshleeb.com/posts/content-defined-chunking.html&quot;&gt;content-defined chunking&lt;/a&gt; algorithm. Doing so means that two similar artifacts can share some underlying data, reducing the total amount of data stored in the the cache. Actually, the new cache uses &lt;em&gt;less&lt;/em&gt; storage space than the data used by the registry for the same set of artifacts!&lt;/p&gt;
&lt;p&gt;That said, the registry isn&apos;t going away either-- it&apos;s still used for mapping project names to project hashes. That is, when you run &lt;code&gt;brioche run -r hello_world&lt;/code&gt;, the registry is used to determine which files to fetch from the cache for the name &lt;code&gt;hello_world&lt;/code&gt;. But, if you were running a custom registry, you&apos;ll either want to migrate to a cache &lt;em&gt;in parallel&lt;/em&gt;, or move entirely to using the new cache system.&lt;/p&gt;
&lt;p&gt;Anyway, I plan on writing more in-depth on how the new cache works and especially the details of the custom archive format soon&lt;/p&gt;
&lt;h3&gt;Cache migration&lt;/h3&gt;
&lt;p&gt;Oh, and to follow up on the cache, I migrated all existing artifacts/bakes/projects from the existing registry to the new cache, which is already configured to be used by default when building Brioche from &lt;code&gt;main&lt;/code&gt; today. The new code will also ensure all &lt;code&gt;brioche-packages&lt;/code&gt; builds will be uploaded both to the legacy registry and to the new cache in parallel.&lt;/p&gt;
&lt;p&gt;For the next release, migrating over to the new cache should be completely seamless&lt;/p&gt;
&lt;h3&gt;Support for unarchiving zip files&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/176&quot;&gt;#176&lt;/a&gt;, &lt;a href=&quot;https://github.com/paricbat&quot;&gt;&lt;strong&gt;@paricbat&lt;/strong&gt;&lt;/a&gt; updated Brioche&apos;s &lt;code&gt;unarchive&lt;/code&gt; recipes to support unarchiving zip files! These work just like tar files, except the option to additionally decompress the file first isn&apos;t supported (since zip files natively handle compression internally).&lt;/p&gt;
&lt;p&gt;The changes on the &lt;code&gt;std&lt;/code&gt; side will be published following the next Brioche release, so the following will work:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const source = Brioche.download(
  &quot;https://github.com/brioche-dev/brioche/archive/refs/tags/v0.1.4.zip&quot;,
).unarchive(&quot;zip&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;LSP fixes and tweaks&lt;/h3&gt;
&lt;p&gt;While working on the new cache, I ended up &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/186&quot;&gt;causing a regression&lt;/a&gt; in the LSP code...&lt;/p&gt;
&lt;p&gt;That was enough motivation to sit down and finally write some integration tests for the LSP server. Along the way, I found and fixed some &lt;em&gt;other&lt;/em&gt; LSP bugs while fixing the regression, which all landed in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/188&quot;&gt;#188&lt;/a&gt;. There were quite a few fixes, so check the PR for details.&lt;/p&gt;
&lt;p&gt;I also made a minor tweak to the LSP: the LSP server will no longer remove unused dependencies from the lockfile on save. The main motivation is that I felt the current behavior could be surprising if you commented then uncommented part of a file. You can read more about the change in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/192&quot;&gt;#192&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;brioche fmt&lt;/code&gt; fix&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/190&quot;&gt;#190&lt;/a&gt; to fix a bug with &lt;code&gt;brioche fmt&lt;/code&gt;. If you didn&apos;t &lt;em&gt;explicitly&lt;/em&gt; specify a project path with &lt;code&gt;-p&lt;/code&gt;, the command would just exit without doing anything! The PR fixed this, defaulting to the current directory if no project path is provided.&lt;/p&gt;
&lt;h3&gt;More work on auto-updates and tests&lt;/h3&gt;
&lt;p&gt;Since &lt;a href=&quot;/blog/project-update-2025-01#progress-on-package-auto-updates-and-tests&quot;&gt;last month&lt;/a&gt;, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; has started adding a ton more &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;autoUpdate&lt;/code&gt; scripts to tons of packages. Some of the newly-added packages have these functions too, so as we make progress on &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/94&quot;&gt;#94&lt;/a&gt; and &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/165&quot;&gt;#165&lt;/a&gt;, a lot of packages should be ready to go on day one for automated tests and auto-updates!&lt;/p&gt;
&lt;h3&gt;Recursive import troubles&lt;/h3&gt;
&lt;p&gt;While working on &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/228&quot;&gt;adding libpsl support to curl&lt;/a&gt;, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; hit a case where two packages would need to &lt;code&gt;import&lt;/code&gt; each other, which straight-up doesn&apos;t work today.&lt;/p&gt;
&lt;p&gt;After a lot of trial and error, we came to the conclusion that there wouldn&apos;t be a satisfying way to work around this problem. So, I opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/175&quot;&gt;#175&lt;/a&gt; to track work on adding circular project dependencies. I haven&apos;t gotten very far with the implementation yet, but it&apos;s my highest priority currently, and I&apos;m hoping to get a PR up in short order.&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;9&lt;/strong&gt; new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;seaweedfs&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/213&quot;&gt;#213&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libffi&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/215&quot;&gt;#215&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aws_cli&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/217&quot;&gt;#217&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libpsl&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/224&quot;&gt;#224&lt;/a&gt;, thanks &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;github_cli&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/225&quot;&gt;#225&lt;/a&gt;, thanks &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nasm&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/229&quot;&gt;#229&lt;/a&gt;, thanks &lt;a href=&quot;https://github.com/paricbat&quot;&gt;&lt;strong&gt;@paricbat&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;steampipe&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/234&quot;&gt;#234&lt;/a&gt;, thanks &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;restic&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/240&quot;&gt;#240&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;claude_code&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/243&quot;&gt;#243&lt;/a&gt;, thanks &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;$BRIOCHE_DATA_DIR&lt;/code&gt; env var to override main Brioche path used for storing data (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/171&quot;&gt;#171&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add support for unarchiving zip files (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/176&quot;&gt;#176&lt;/a&gt; by &lt;a href=&quot;https://github.com/paricbat&quot;&gt;&lt;strong&gt;@paricbat&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;New cache (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/179&quot;&gt;#179&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;Enable conditional PUTs for S3 object store (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/181&quot;&gt;#181&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add config option to allow for HTTP-only cache requests (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/182&quot;&gt;#182&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Tweak how cache fetch jobs are displayed in plain output format (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/183&quot;&gt;#183&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Enable some more Clippy lints (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/185&quot;&gt;#185&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix miscellaneous bugs in LSP (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/188&quot;&gt;#188&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Default &lt;code&gt;brioche fmt&lt;/code&gt; to &lt;code&gt;.&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/190&quot;&gt;#190&lt;/a&gt; by &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Tweak LSP to keep unused dependencies when saving (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/192&quot;&gt;#192&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - January 2025</title><link>https://brioche.dev/blog/project-update-2025-01</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2025-01</guid><pubDate>Mon, 27 Jan 2025 07:19:42 GMT</pubDate><content:encoded>&lt;p&gt;It&apos;s been a while since I got a Project Update out. December was a turbulent month for me-- we had a loss in the family, we were out of town for a while, and I was sick for a while. And beyond all that, it was nice to unplug for a while to spend time with friends and family over the holidays too.&lt;/p&gt;
&lt;p&gt;...anyway, since the start of the year, I&apos;ve definitely picked up steam on Brioche again, and a lot has happened &lt;a href=&quot;project-update-2024-11.md&quot;&gt;since the last update in November!&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Status report&lt;/h2&gt;
&lt;h3&gt;Brioche v0.1.4 released&lt;/h3&gt;
&lt;p&gt;About a week ago, I published &lt;a href=&quot;/blog/announcing-brioche-v0-1-4/&quot;&gt;Brioche v0.1.4&lt;/a&gt;! There were some fun headline features, but to me this release was more about finally getting a few incremental improvements out in the wild.&lt;/p&gt;
&lt;h3&gt;CMake&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/144&quot;&gt;brioche-packages#144&lt;/a&gt; introduced a new package for CMake. A simple &lt;code&gt;project.bri&lt;/code&gt; for a CMake project might look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * as std from &quot;std&quot;;
import { cmakeBuild } from &quot;cmake&quot;;

export default function (): std.Recipe&amp;lt;std.Directory&amp;gt; {
  return cmakeBuild({
    source: Brioche.glob(&quot;CMakeLists.txt&quot; /* build files */),
    dependencies: [std.toolchain() /* other deps */],
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The biggest challenge here was to do with &lt;a href=&quot;/docs/how-it-works/packed-executables/&quot;&gt;packed executables&lt;/a&gt;. It turns out CMake, in some cases, will try to update an executable&apos;s rpath after the build. Brioche&apos;s packed executable format interfered with CMake&apos;s logic here, so I ended up introducing a patch to the CMake build.&lt;/p&gt;
&lt;p&gt;This patch updates CMake to look for Brioche&apos;s packed executables, and-- if found-- applies the rpath logic to the unpacked executable, then re-packs it. For normal non-packed executables, this logic works exactly the same, so you can use Brioche&apos;s version of CMake for totally normal builds too-- say, by running &lt;code&gt;brioche install -r cmake&lt;/code&gt;!&lt;/p&gt;
&lt;h3&gt;Ubuntu troubles&lt;/h3&gt;
&lt;p&gt;I finally decided to update our GitHub Actions workflows from Ubuntu 22.04 to Ubuntu 24.04. That sent me down a rabbit hole, where I discovered that &lt;a href=&quot;https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces&quot;&gt;Ubuntu 23.10 started restricting user namespaces by default&lt;/a&gt;. Brioche uses user namespaces for build sandboxing, so this means &lt;strong&gt;Brioche builds don&apos;t work on Ubuntu out-of-the-box!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This led to a few outcomes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I updated the main Brioche build to use Ubuntu 24.04, but added a sysctl config to &quot;un-restrict&quot; user namespaces (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/151&quot;&gt;brioche#151&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;I updated the &lt;a href=&quot;https://github.com/brioche-dev/setup-brioche&quot;&gt;&lt;code&gt;setup-brioche&lt;/code&gt;&lt;/a&gt; GitHub Action to try installing an AppArmor profile, if it seems like it&apos;s needed (&lt;a href=&quot;https://github.com/brioche-dev/setup-brioche/pull/2&quot;&gt;setup-brioche#2&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;As part of the Brioche v0.1.4 release, I added a sandboxing fallback using &lt;a href=&quot;https://proot-me.github.io/&quot;&gt;PRoot&lt;/a&gt;. This has a performance penalty, but it makes sure Brioche can work out-of-the-box on Ubuntu 24.04 (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/159&quot;&gt;brioche#159&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The work on the sandboxing fallback ended up taking me a lot longer than I expected. There were some false starts, but using PRoot seemed to be the most reasonable direction here. Specifically, we run PRoot within a namespace-- Ubuntu 24.04 lets you create an unprivileged user namespace, but prevents you from creating &lt;em&gt;mounts&lt;/em&gt; within an unprivileged namespace.&lt;/p&gt;
&lt;p&gt;So the idea is that we use namespaces just like we did before, except if using mounts fails for isolating the filesystem, we&apos;ll use PRoot instead (e.g. on Ubuntu 24.04).&lt;/p&gt;
&lt;p&gt;PRoot definitely isn&apos;t a perfect solution, but it was the best solution that I could adopt easily. I also looked into using &lt;a href=&quot;https://en.wikipedia.org/wiki/User-mode_Linux&quot;&gt;User-mode Linux&lt;/a&gt;, but everything I&apos;ve read about it suggests it&apos;s not really meant as a sandboxing tool... plus I wasn&apos;t able to compile a working build of it. Longer-term, if Brioche is going to need sandboxing option like PRoot, I think it&apos;d be interesting to build a DIY solution: a built-in ptrace-based sandboxing tool, but tailored for Brioche&apos;s sandboxing needs.&lt;/p&gt;
&lt;p&gt;Shorter-term, I&apos;d also like to add more sandboxing options. The next one would be an &quot;unsandboxed&quot; sandboxing mode, and later followed by a &quot;qemu&quot; sandboxing mode. I don&apos;t think either would be a good default, but would be a good option if you&apos;re using, say, Ubuntu 24.04 and want better performance than PRoot, but don&apos;t want to (or can&apos;t) lift the user namespace restrictions.&lt;/p&gt;
&lt;h3&gt;Sync speedup&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/pzmarzly&quot;&gt;&lt;strong&gt;@pzmarzly&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/147&quot;&gt;brioche#147&lt;/a&gt;, pointing out that syncing &lt;code&gt;std.toolchain()&lt;/code&gt; for a minimal example build is really slow. I think solving this issue would be really valuable-- not just for first-time users, but also because &lt;code&gt;brioche-packages&lt;/code&gt; builds start from a blank slate, meaning that this issue compounds &lt;em&gt;a lot&lt;/em&gt; over time.&lt;/p&gt;
&lt;p&gt;Today, things should be a lot better than when the issue was first opened, but it involved a few moving pieces: first, I added the new &lt;code&gt;attach_resources&lt;/code&gt; recipe (discussed in &lt;a href=&quot;/blog/announcing-brioche-v0-1-4/#new-recipe-attach_resources&quot;&gt;the v0.1.4 announcement&lt;/a&gt; and from &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/149&quot;&gt;brioche#149&lt;/a&gt;). Then, I updated the &lt;code&gt;std&lt;/code&gt; package to sync &lt;code&gt;std.toolchain()&lt;/code&gt; as a tarball using the &lt;code&gt;attach_resources&lt;/code&gt; recipe (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/147&quot;&gt;brioche-packages#147&lt;/a&gt;). Combined, &lt;code&gt;std.toolchain()&lt;/code&gt; will now get delivered from the registry as one big tarball instead of thousands of tiny files-- much faster!&lt;/p&gt;
&lt;p&gt;I still have more ideas for speeding up syncing in general, so I didn&apos;t feel ready to close out &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/147&quot;&gt;brioche#147&lt;/a&gt; yet-- expect more updates here for next month!&lt;/p&gt;
&lt;h3&gt;aarch64 work&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/150&quot;&gt;brioche#150&lt;/a&gt; introduced support for &lt;code&gt;aarch64-linux&lt;/code&gt; builds in Brioche! This means you can now build packages targetting Linux on either aarch64 or x86-64 now!&lt;/p&gt;
&lt;p&gt;...but, to make that &lt;em&gt;usable&lt;/em&gt;, packages need to be built to support aarch64 as well. If you check out the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/tree/wip/aarch64-linux&quot;&gt;&lt;code&gt;wip/aarch64-linux&lt;/code&gt;&lt;/a&gt; branch, running &lt;code&gt;brioche build -p packages/std -e toolchain&lt;/code&gt; &lt;em&gt;works&lt;/em&gt;, and will create a toolchain for aarch64. I also verified that at least &lt;code&gt;curl&lt;/code&gt; also builds with the toolchain changes!&lt;/p&gt;
&lt;p&gt;But, the branch is not mergeable in its current state. There&apos;s no way for a recipe to choose between doing an x86-64 build or an aarch64 build right now. I&apos;ve got an idea on how the host / target platform can get threaded down through recipes, but it&apos;ll take some work to implement. And, I&apos;d like to hold that off until after doing some refactoring to the code first.&lt;/p&gt;
&lt;p&gt;TL;DR: aarch64 works right now if you&apos;re willing to build from-source from a branch, but it&apos;s going to take some work to get everything playing nicely together.&lt;/p&gt;
&lt;h3&gt;Brioche-in-Brioche&lt;/h3&gt;
&lt;p&gt;As mentioned in the v0.1.4 announcement, &lt;a href=&quot;/blog/announcing-brioche-v0-1-4/#packed-builds-of-brioche&quot;&gt;Brioche can now build itself&lt;/a&gt;! For releases, this is useful because it leads to a packed build, which is fully portable despite Brioche itself targetting glibc.&lt;/p&gt;
&lt;p&gt;(This also led to some changes to the install script, you can read about all the new options in the &lt;a href=&quot;/docs/installation/&quot;&gt;&quot;Installation&quot; docs&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;For development, this is also pretty cool because you can now test your changes locally, and you&apos;ll get feedback beyond what you&apos;d get just using &lt;code&gt;cargo run&lt;/code&gt;! For example, if you update the JS runtime package under &lt;code&gt;crates/brioche-core/runtime&lt;/code&gt; but &lt;em&gt;don&apos;t&lt;/em&gt; rebuild it, you&apos;ll get an error during the build. We were already explicitly checking for this in our GitHub Actions workflow, but it&apos;s nice to have an easy way to run some CI-only checks locally without needing to install new tools. Oh, and you can also use &lt;code&gt;brioche build -e runtime&lt;/code&gt; to rebuild / update the runtime too, even if you don&apos;t have your own NodeJS toolchain set up locally.&lt;/p&gt;
&lt;h3&gt;Performance optimizations&lt;/h3&gt;
&lt;p&gt;I spent some time cleaning up Brioche&apos;s Tracing / OpenTelemetry output in &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/168&quot;&gt;brioche#168&lt;/a&gt;, which makes it much easier to dig into performance issues.&lt;/p&gt;
&lt;p&gt;That led me to find some low-hanging fruit for optimization, so I opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/169&quot;&gt;brioche#169&lt;/a&gt;, which can drastically speed up cache hits when preparing to do a build! For a (failing) test build, the time for the build to exit dropped from 15.51 seconds down to 1.12 seconds!&lt;/p&gt;
&lt;h3&gt;Progress on package auto-updates and tests&lt;/h3&gt;
&lt;p&gt;For a while, I&apos;ve had in mind some ways we could automate simple package updates. Well, &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; started picking up the work here and updated the &lt;code&gt;alsa_lib&lt;/code&gt; package in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/211&quot;&gt;brioche-packages#211&lt;/a&gt; as the first step to landing this work!&lt;/p&gt;
&lt;p&gt;The end goal will make it so routine package updates won&apos;t require any manual code changes: a simple CI pipeline should be able to handle the version bump in the &lt;code&gt;project.bri&lt;/code&gt; file, then automatically run tests to catch any regressions. There will still be plenty of work for manual review and testing, but getting the routine work handled automatically should help a ton for keeping packages up-to-date.&lt;/p&gt;
&lt;h2&gt;Housekeeping&lt;/h2&gt;
&lt;h3&gt;New packages&lt;/h3&gt;
&lt;p&gt;Since the last update, there were &lt;strong&gt;13&lt;/strong&gt; new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cmake&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/144&quot;&gt;#144&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pstack&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/145&quot;&gt;#145&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;talloc&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/150&quot;&gt;#150&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libarchive&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/151&quot;&gt;#151&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proot&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/152&quot;&gt;#152&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fx&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/154&quot;&gt;#154&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dasel&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/155&quot;&gt;#155&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scdoc&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/157&quot;&gt;#157&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kmod&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/158&quot;&gt;#158&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s2argv_execs&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/159&quot;&gt;#159&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vdeplug4&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/160&quot;&gt;#160&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;linux&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/161&quot;&gt;#161&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;just&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/168&quot;&gt;#168&lt;/a&gt;, thanks &lt;a href=&quot;https://github.com/paricbat&quot;&gt;&lt;strong&gt;@paricbat&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There was also one extra package (&lt;code&gt;jj&lt;/code&gt;) which was added in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/148&quot;&gt;brioche-packages#148&lt;/a&gt;. &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; pointed out that this was redundant with the existing &lt;code&gt;jujutsu&lt;/code&gt; package, so &lt;code&gt;jj&lt;/code&gt; was removed (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/187&quot;&gt;brioche-packages#187&lt;/a&gt;). Oops...&lt;/p&gt;
&lt;p&gt;And huge kudos to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt;, who also updated 37 packages over the past week!&lt;/p&gt;
&lt;h3&gt;Brioche core updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;--display&lt;/code&gt; flag to explicitly choose an output format (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/141&quot;&gt;#141&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;The new &lt;code&gt;--display plain-reduced&lt;/code&gt; format is now used in the &lt;code&gt;brioche-packages&lt;/code&gt; repo (see &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/143&quot;&gt;brioche-packages#143&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Add frame to process events after writing description (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/144&quot;&gt;#144&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add initial support for &lt;code&gt;aarch64&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/150&quot;&gt;#150&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix OpenTelemetry runtime and shutdown (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/142&quot;&gt;#142&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;project.bri&lt;/code&gt; to build Brioche with Brioche (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/157&quot;&gt;#157&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update Linux sandbox to fallback to using PRoot for mounts (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/159&quot;&gt;#159&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Clean up tracing output (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/168&quot;&gt;#168&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Speed up outputs and fetching blobs (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/169&quot;&gt;#169&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Disable self-update commands in packed Brioche builds (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/161&quot;&gt;#161&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update installation script in README (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/163&quot;&gt;#163&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update Cargo workspace and resolve a few lints on Darwin (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/164&quot;&gt;#164&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update Rust version to 1.84 in Cargo.toml files (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/167&quot;&gt;#167&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Update tokio-utils features (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/170&quot;&gt;#170&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;setup-brioche action updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Add AppArmor profile to fix Brioche builds on Ubuntu 24.04 (&lt;a href=&quot;https://github.com/brioche-dev/setup-brioche/pull/2&quot;&gt;#2&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;Can also control this behavior explicitly with the new &lt;code&gt;install-apparmor&lt;/code&gt; input value&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Project update&lt;/h3&gt;
&lt;p&gt;I&apos;ve been pretty loose with the structure of the project updates. I decided to try breaking it up into the &quot;status report&quot; with a little more in-depth discusion, and &quot;housekeeping&quot; with bulleted notes, mainly summarizing stuff from GitHub PRs.&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Announcing Brioche v0.1.4</title><link>https://brioche.dev/blog/announcing-brioche-v0-1-4</link><guid isPermaLink="true">https://brioche.dev/blog/announcing-brioche-v0-1-4</guid><pubDate>Sun, 19 Jan 2025 07:26:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://brioche.dev/&quot;&gt;Brioche&lt;/a&gt; is a new package manager and build tool that makes it easy to mix and match languages and tools for your own development projects.&lt;/p&gt;
&lt;p&gt;Today marks the release of Brioche v0.1.4-- over 3 months in the making since our last release, and the fourth version after the &lt;a href=&quot;https://brioche.dev/blog/announcing-brioche/&quot;&gt;public release in July&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;New console output&lt;/h2&gt;
&lt;p&gt;My personal favorite feature, and the one that&apos;s most fun to show off, is the new TUI-style console output you see during a build. Compared to &lt;a href=&quot;https://asciinema.org/a/9W15OfFdkIljSS2tVrIlWKIlX&quot;&gt;the old console output&lt;/a&gt;, the new format is colorful, cleaner, and more clearly organized. Plus, it runs at a higher refresh rate, so it &lt;em&gt;feels&lt;/em&gt; a lot snappier. And here&apos;s what it looks like:&lt;/p&gt;
&lt;p&gt;&amp;lt;div&amp;gt;
&amp;lt;script src=&quot;https://asciinema.org/a/681816.js&quot; id=&quot;asciicast-681816&quot; async=&quot;true&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h2&gt;New format for process failures&lt;/h2&gt;
&lt;p&gt;Nothing&apos;s worse than following along with the instructions on building a program from source, only to get a build error &lt;em&gt;despite&lt;/em&gt; doing everything the documentation says. Well, getting a build error and not being able to see what the error was might be worse...&lt;/p&gt;
&lt;p&gt;Up until now, if a process recipe failed to bake, you&apos;d get an error message helpfully pointing you to two files: &lt;code&gt;stdout.txt&lt;/code&gt; and &lt;code&gt;stderr.txt&lt;/code&gt;. As you might&apos;ve guessed, these files contained the stdout and stderr streams of the failed process, respectively.&lt;/p&gt;
&lt;p&gt;This definitely helped give &lt;em&gt;some&lt;/em&gt; context on what went wrong. But, since stdout and stderr were written separately, if a process interleaved messages on both streams, it might be impossible to figure out &lt;em&gt;when&lt;/em&gt; or &lt;em&gt;where&lt;/em&gt; an error happened. While Brioche would print a stack trace on failure, it didn&apos;t persist the stack trace anywhere, so working backwards from the files &lt;code&gt;stdout.txt&lt;/code&gt; / &lt;code&gt;stderr.txt&lt;/code&gt;, it could be hard to even find out &lt;em&gt;what&lt;/em&gt; failed!&lt;/p&gt;
&lt;p&gt;In the latest release, build failures are definitely still painful, but a &lt;em&gt;little&lt;/em&gt; less. Now, Brioche records a bunch more details on process failure in a new combined file format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stdout and stderr get saved in the same file, preserving how output was interleaved&lt;/li&gt;
&lt;li&gt;Details about the failed process recipe are recorded, including a full stack trace of your &lt;code&gt;.bri&lt;/code&gt; code&lt;/li&gt;
&lt;li&gt;We also save the process exit status and a timestamp for each output line for good measure&lt;/li&gt;
&lt;li&gt;Oh, and the new format is compressed! I even ended up writing a new Rust crate (&lt;a href=&quot;https://crates.io/crates/zstd-framed&quot;&gt;&lt;code&gt;zstd-framed&lt;/code&gt;&lt;/a&gt;) to handle the compression while keeping the format seekable (which I wrote about in the &lt;a href=&quot;/blog/project-update-2024-11&quot;&gt;November Project Update&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyway, the important part is, when a process fails, the error message will tell you to run a command like this: &lt;code&gt;brioche jobs logs /path/to/events.bin.zst&lt;/code&gt;. If you do so, you&apos;ll see much more detail about the failed process than what you got before:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ brioche jobs logs /home/user/.local/share/brioche/process-temp/01JCYC3PN9QHFJDD6R41KRTDMB/events.bin.zst
process stack trace:
- file:///home/user/.local/share/brioche/projects/97beeb18f169ced9073a4f542f4195ef675ca4b1407170a247485c21545987bf/extra/run_bash.bri:42:14
- file:///home/user/example-project/project.bri:4:21

[0.00s] [spawned process with pid 109069, preparation took 0.01s]
[0.01s] uh oh, build failed
[0.01s] [process exited with code 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CLI improvements&lt;/h2&gt;
&lt;p&gt;Like other package managers, several Brioche subcommands now have a &lt;code&gt;--locked&lt;/code&gt; flag. This will prevent Brioche from updating your lockfile: if the lockfile is out of date, the command will instead error out. This is a perfect fit for CI/CD pipelines, where you want to make sure your lockfiles are committed to the repo properly.&lt;/p&gt;
&lt;p&gt;Also, CLI commands take a new &lt;code&gt;--display&lt;/code&gt; flag. With this, you can force Brioche to output plaintext only instead of using a TUI-style view (&lt;code&gt;--display plain&lt;/code&gt;), or you can force it to output in TUI mode explicitly (&lt;code&gt;--display console&lt;/code&gt;). Additionally, there&apos;s a brand new &lt;em&gt;reduced&lt;/em&gt; display mode (&lt;code&gt;--display plain-reduced&lt;/code&gt;), which is the same as plaintext, except it&apos;s less verbose. We now use this in the &lt;code&gt;brioche-packages&lt;/code&gt; repo to avoid outputting an absurd amount of text during the GitHub Actions build, and it might be a good choice any time you have an overly-noisy or long-running build.&lt;/p&gt;
&lt;h2&gt;New recipe: &lt;code&gt;attach_resources&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This release includes a new &lt;code&gt;attach_resources&lt;/code&gt; recipe. This is really a lower level tool that I don&apos;t really expect to be used outside the &lt;code&gt;std&lt;/code&gt; package, but the goal is to help optimize how large recipes get served from the registry.&lt;/p&gt;
&lt;p&gt;Okay, let&apos;s get in the weeds a little: &lt;a href=&quot;/docs/core-concepts/artifacts#files&quot;&gt;file artifacts&lt;/a&gt; can have a &quot;resource directory&quot; attached, where the contents of the directory will be &quot;nearby&quot; at runtime. This is a core ingredient for &lt;a href=&quot;/docs/how-it-works/packed-executables&quot;&gt;packed executables&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The challenge is that resources are kinda lossy, and moving them into and out of processes can sometimes &quot;lose&quot; the resources if not handled properly. So, back in &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.1&quot;&gt;Brioche v0.1.1&lt;/a&gt;, we added the new &lt;code&gt;collect_references&lt;/code&gt; recipe, which basically collects all the resources used in a directory and puts them within a subdirectory named &lt;code&gt;brioche-resources.d&lt;/code&gt;, then detaches the files from their resources. &lt;code&gt;attach_resources&lt;/code&gt; is the inverse[^attach-resources-and-collect-references-naming]: given a directory, it looks for each file&apos;s resources by looking under &lt;code&gt;brioche-resources.d&lt;/code&gt;, and reattaches them. Together, these can be used to round-trip a recipe into a tar file and back out again, preserving the recipes on either side.&lt;/p&gt;
&lt;p&gt;So, circling back to speeding up registry syncs: &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/147&quot;&gt;@pzmarzly&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/147&quot;&gt;#147&lt;/a&gt; becuase, when trying to build one of the example projects, the initial registry sync took over 15 minutes! I had the idea to speed up the download of the &lt;code&gt;std.toolchain()&lt;/code&gt; recipe by serving it as a single tar file, but to do so, Brioche needed a way to tar up a recipe and untar it &lt;em&gt;while keeping the references in tact&lt;/em&gt;. With the new &lt;code&gt;attach_resources&lt;/code&gt; recipe, this should be now be pretty easy!&lt;/p&gt;
&lt;h2&gt;Packed builds of Brioche&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/matklad&quot;&gt;@matklad&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/51&quot;&gt;#51&lt;/a&gt; following Brioche&apos;s public release, asking for a fully static build so it can work on non-glibc-based Linux distros-- and specifically for NixOS.&lt;/p&gt;
&lt;p&gt;Not that long ago, I wrote about &lt;a href=&quot;/blog/portable-dynamically-linked-packages-on-linux&quot;&gt;how Brioche builds portable packages on Linux&lt;/a&gt;, so it&apos;s a bit embarrassing that Brioche &lt;em&gt;itself&lt;/em&gt; wasn&apos;t distributed that way...&lt;/p&gt;
&lt;p&gt;Well, as of this release, Brioche has its own &lt;code&gt;project.bri&lt;/code&gt; and can build itself! The result is fully portable and should work on any x86-64 Linux system, including distributions without glibc installed globally like NixOS and Alpine Linux.&lt;/p&gt;
&lt;p&gt;Shortly after the release goes live, I&apos;ll work on updating the Brioche install script. For starters, this packed build will be used as a fallback, and the default will still be to install the glibc-based executable. Packed builds &lt;strong&gt;don&apos;t support automatic updates yet&lt;/strong&gt;, so there&apos;s more work to do.&lt;/p&gt;
&lt;p&gt;In the coming release(s), I&apos;m hoping to build on this work: add support for automatic updates, switch to the packed builds as the default, and offer a migration path for existing installations during automatic updates. But this first milestone should make it possible for more people to try out Brioche today!&lt;/p&gt;
&lt;h2&gt;Linux sandboxing fallback with PRoot&lt;/h2&gt;
&lt;p&gt;Recently, I worked on upgrading all of our GitHub Actions pipelines from Ubuntu 22.04 to 24.04. I thought this would be frictionless, but I was very wrong...&lt;/p&gt;
&lt;p&gt;In Ubuntu 23.10, &lt;a href=&quot;https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces&quot;&gt;Ubuntu started restricting unprivileged user namespaces by default&lt;/a&gt;, which is the basis for how &lt;a href=&quot;/docs/how-it-works/sandboxing&quot;&gt;sandboxing&lt;/a&gt; works on Linux. Ubuntu 24.04 &lt;a href=&quot;https://ubuntu.com/blog/whats-new-in-security-for-ubuntu-24-04-lts#:~:text=22.04%20LTS.-,Unprivileged%20user%20namespace%20restrictions,-Unprivileged%20user%20namespaces&quot;&gt;loosened the restrictions a little&lt;/a&gt;, but the end result was that Brioche didn&apos;t work out of the box by default on Ubuntu 24.04.&lt;/p&gt;
&lt;p&gt;For our internal GitHub Actions workflows, it was easy enough to use some &lt;code&gt;sysctl&lt;/code&gt; commands to allow unprivileged user namespaces. For our public &lt;a href=&quot;https://github.com/brioche-dev/setup-brioche&quot;&gt;&lt;code&gt;setup-brioche&lt;/code&gt; action&lt;/a&gt;, we also now try to install an AppArmor profile if needed (&lt;a href=&quot;https://github.com/brioche-dev/setup-brioche/pull/2&quot;&gt;brioche-dev/setup-brioche#2&lt;/a&gt;), which should help avoid any issues for GitHub Actions workflows in most cases.&lt;/p&gt;
&lt;p&gt;But for end users, I still wanted Brioche to work without any extra setup and without needing root to grant extra permissions. So now, Brioche will try to detect if it&apos;s able to use namespaces for sandboxing-- the same as before. If that doesn&apos;t work, it&apos;ll now fallback to sandboxing using namespaces along with &lt;a href=&quot;https://proot-me.github.io/&quot;&gt;PRoot&lt;/a&gt; (as introduced by &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/159&quot;&gt;#159&lt;/a&gt;). Failing that, it&apos;ll return an error. Using PRoot does come with a notable performance impact (see &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/159#issuecomment-2589262344&quot;&gt;this comment&lt;/a&gt;), so it prints a warning (by default) if it needs to be used. &lt;a href=&quot;/docs/configuration#sandbox-configuration&quot;&gt;You can also manually tweak the config for more control over sandboxing now&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Despite the performance impact, I feel pretty good about falling back to PRoot, so Brioche works without any extra setup on Ubuntu 24.04 (I believe Ubuntu 23.10 &lt;em&gt;won&apos;t&lt;/em&gt; work, although I haven&apos;t tested it). And over time, Brioche will definitely gain more options for sandboxing, in order to balance the tradeoffs between performance, isolation, and host compatibility.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Anyway, Brioche v0.1.4 is live now! If you already have it installed, run &lt;code&gt;brioche self-update&lt;/code&gt; and follow the prompts to update to the latest version. Or, if you haven&apos;t tried out Brioche yet, check out &lt;a href=&quot;/docs/installation&quot;&gt;installation options in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and rolling out the new &lt;a href=&quot;#packed-builds-of-brioche&quot;&gt;packed builds&lt;/a&gt; will take a little extra work post-release, so keep an eye on the docs for additional information shortly.&lt;/p&gt;
&lt;p&gt;Questions, help, and feedback are always welcome on Brioche&apos;s &lt;a href=&quot;https://github.com/brioche-dev/brioche&quot;&gt;GitHub&lt;/a&gt;, &lt;a href=&quot;https://discord.gg/cw5QeWv4E5&quot;&gt;Discord&lt;/a&gt;, and &lt;a href=&quot;https://brioche.zulipchat.com/&quot;&gt;Zulip&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;[^attach-resources-and-collect-references-naming]: Yes, one of the recipes is named &quot;collect &lt;em&gt;references&lt;/em&gt;&quot; and the other is named &quot;attach &lt;em&gt;resources&lt;/em&gt;&quot;, and these recipes are effectively opposites of each other. I don&apos;t like the split in the &quot;references&quot; / &quot;resources&quot; terminology, and I don&apos;t think &quot;collect&quot; and &quot;attach&quot; really make it clear these recipes are complimentary. I&apos;d like to try to come up with better names in a future release (open to bike-shedding!)&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - November 2024</title><link>https://brioche.dev/blog/project-update-2024-11</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2024-11</guid><pubDate>Mon, 18 Nov 2024 07:53:23 GMT</pubDate><content:encoded>&lt;p&gt;The last month (and change) has been one of rabbit holes!&lt;/p&gt;
&lt;h2&gt;Package updates&lt;/h2&gt;
&lt;p&gt;Since the last update, there were 11 new packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tcpdump&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libpcap&lt;/code&gt; (thanks to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; for laying out the groundwork!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;python&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wasmtime&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asciinema&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxml2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxslt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;moreutils&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zx&lt;/code&gt; (thanks &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;amber&lt;/code&gt; (thanks &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fd&lt;/code&gt; (thanks &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Python was a big milestone! It was quite fun to puzzle out how package builds look when using Python. You can see &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/e49e2961f463ebd2d017b7dbda64dd1032b4c5f9/packages/asciinema/project.bri&quot;&gt;&lt;code&gt;asciinema&lt;/code&gt;&lt;/a&gt; for what a Python-based build looks like (although projects using Poetry/uv/pyenv/etc will probably end up being quite different-- &lt;code&gt;asciinema&lt;/code&gt; just uses pure Python and pip)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;moreutils&lt;/code&gt; proved to be a surprising challenge-- it&apos;s simple on the surface but it turned out to be hard specifically due to how docs are built. I needed to figure out what an &lt;a href=&quot;https://en.wikipedia.org/wiki/XML_catalog&quot;&gt;&quot;XML catalog&quot;&lt;/a&gt; was, which I used to create &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/e49e2961f463ebd2d017b7dbda64dd1032b4c5f9/packages/moreutils/project.bri#L70&quot;&gt;this ~monstrosity~ beautiful inline XML file&lt;/a&gt; directly in the package definition. &lt;s&gt;(next up: adding JSX support for defining inline XML files more easily in Brioche?)&lt;/s&gt;&lt;/p&gt;
&lt;h2&gt;std updates&lt;/h2&gt;
&lt;p&gt;There were a few disperate changes in &lt;code&gt;std&lt;/code&gt; since last update. Full changes in &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/main/packages/std/CHANGELOG.md#2024-10-12&quot;&gt;the changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There was a breaking change around the &lt;code&gt;std.process()&lt;/code&gt; function-- the &lt;code&gt;unsafe&lt;/code&gt; options have been reorganized to be more composable. The &lt;code&gt;rust&lt;/code&gt; package is now taking advantage of this as of &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/123&quot;&gt;brioche-dev/brioche-packages#123&lt;/a&gt;, where it passes through all unsafe options directly to the underlying &lt;code&gt;std.process()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There were also two new functions used to create &lt;a href=&quot;https://brioche.dev/docs/core-concepts/runnables/&quot;&gt;&quot;runnables&quot;&lt;/a&gt; (this also included a minor breaking change around process template symbols). The new functions &lt;code&gt;std.withRunnable()&lt;/code&gt; and &lt;code&gt;std.addRunnable()&lt;/code&gt; provide a nice alternative to the very bare-bones &lt;code&gt;std.withRunnableLink()&lt;/code&gt; function, and the heavy-handed &lt;code&gt;std.bashRunnable&lt;/code&gt; template function that pulls in Bash as a dependency.&lt;/p&gt;
&lt;p&gt;Finally, there were a few minor changes around the toolchain to sand off a few more sharp edges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fix typo in &lt;code&gt;$PERL5LIB&lt;/code&gt; env var&lt;/li&gt;
&lt;li&gt;Fix broken library symlinks&lt;/li&gt;
&lt;li&gt;Patch &lt;code&gt;pkg-config&lt;/code&gt; files to use relative paths. We&apos;ll probably want to provide a general mechanism for this, but for now it&apos;s been copy/pasted to a few other packages (see &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/issues/135&quot;&gt;brioche-dev/brioche-packages#135&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;$BISON_PKGDATADIR&lt;/code&gt; to fix Bison&lt;/li&gt;
&lt;li&gt;Set some more symlinks and env vars so more autotools builds &quot;just work&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Brioche core updates&lt;/h2&gt;
&lt;p&gt;Okay, here&apos;s where things get exciting (and also a little complicated!)&lt;/p&gt;
&lt;p&gt;This cycle, I&apos;ve been interested in improving developer ergonomics in preparation to start on cross-platform builds, so I wanted to revisit some of the minor pain points in the flow for building and debugging packages before embarking on that journey.&lt;/p&gt;
&lt;h3&gt;New console output&lt;/h3&gt;
&lt;p&gt;I was getting pretty tired of the &quot;pretty&quot; output that the CLI currently uses... so I redesigned it!&lt;/p&gt;
&lt;p&gt;Here&apos;s a side-by-side between the current version in Brioche v0.1.3 and the new one as of &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/137&quot;&gt;brioche-dev/brioche#137&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;flex flex-col gap-x-4 content-between md:flex-row md:relative md:p-8 md:extrawide&quot;&amp;gt;
&amp;lt;div class=&quot;flex-1&quot;&amp;gt;
&amp;lt;a href=&quot;https://asciinema.org/a/9W15OfFdkIljSS2tVrIlWKIlX&quot; class=&quot;text-center block&quot;&amp;gt;Before&amp;lt;/a&amp;gt;
&amp;lt;script src=&quot;https://asciinema.org/a/9W15OfFdkIljSS2tVrIlWKIlX.js&quot; id=&quot;asciicast-9W15OfFdkIljSS2tVrIlWKIlX&quot; async=&quot;true&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;flex-1&quot;&amp;gt;
&amp;lt;a href=&quot;https://asciinema.org/a/681816&quot; class=&quot;text-center block&quot;&amp;gt;After&amp;lt;/a&amp;gt;
&amp;lt;script src=&quot;https://asciinema.org/a/681816.js&quot; id=&quot;asciicast-681816&quot; async=&quot;true&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;(You can probably guess why I added the &lt;code&gt;asciinema&lt;/code&gt; package recently!)&lt;/p&gt;
&lt;p&gt;I find the new output much easier to scan personally. The new output also uses a higher framerate, which makes it &quot;feel&quot; faster-- to my eyes at least.&lt;/p&gt;
&lt;h3&gt;New process logging&lt;/h3&gt;
&lt;p&gt;When a build fails in Brioche v0.1.3, you get a &lt;em&gt;very&lt;/em&gt; ugly error message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error: process failed, view full output from these paths:
- /home/user/.local/share/brioche/process-temp/01JCYBMMGZ5QJD61R5Z0H7WZCQ/stdout.log
- /home/user/.local/share/brioche/process-temp/01JCYBMMGZ5QJD61R5Z0H7WZCQ/stderr.log: process exited with status code exit status: 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file paths listed though are pretty helpful! You can see the full stdout/stderr of the failed process (and pro tip: the directories containing those files contain the build&apos;s working directory, making it easy to find things like &lt;code&gt;config.log&lt;/code&gt; files). Lots of process write to both stdout and stderr, but since they get written to separate files, these logs are &lt;em&gt;lossy&lt;/em&gt;, since you lose how the messages get interleaved. In practice, this just makes trawling through failed logs harder than it should be.&lt;/p&gt;
&lt;p&gt;As of &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/138&quot;&gt;brioche-dev/brioche#138&lt;/a&gt;, the error message is... still pretty ugly, but more useful!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error: process failed, view full output by runing `brioche jobs logs /home/user/.local/share/brioche/process-temp/01JCYC3PN9QHFJDD6R41KRTDMB/events.bin.zst`: process exited with status code exit status: 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As hinted by the error message, the separate stdout and stderr files have been replaced with a new mysterious &lt;code&gt;events.bin.zst&lt;/code&gt; file, &lt;em&gt;ooh!&lt;/em&gt; This is a pretty simple (binary) file format that includes &lt;em&gt;both&lt;/em&gt; stdout and stderr, but with lots of fancy bells and whistles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stdout and stderr are interleaved, but each chunk is tagged to indicate which stream it&apos;s from&lt;/li&gt;
&lt;li&gt;Each chunk includes a timestamp&lt;/li&gt;
&lt;li&gt;There&apos;s an event that includes the process exit code at the end (also timestamped)&lt;/li&gt;
&lt;li&gt;There&apos;s an event at the start with lots of metadata about the build, including a stack trace&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we run the suggested &lt;code&gt;brioche jobs logs&lt;/code&gt; command, we get a pretty detailed output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ brioche jobs logs /home/user/.local/share/brioche/process-temp/01JCYC3PN9QHFJDD6R41KRTDMB/events.bin.zst
process stack trace:
- file:///home/user/.local/share/brioche/projects/97beeb18f169ced9073a4f542f4195ef675ca4b1407170a247485c21545987bf/extra/run_bash.bri:42:14
- file:///home/user/example-project/project.bri:4:21

[0.00s] [spawned process with pid 109069, preparation took 0.01s]
[0.01s] uh oh, build failed
[0.01s] [process exited with code 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&apos;s lots of untapped potential with the new process event format, but I&apos;m pretty happy with this as a first pass! &lt;code&gt;brioche jobs&lt;/code&gt; is an entirely new subcommand, and I think it&apos;ll be possible to add lots of handy new utilities for diving in when a build fails.&lt;/p&gt;
&lt;h3&gt;Compression woes&lt;/h3&gt;
&lt;p&gt;Oh, also, you may have noticed the filename above was &lt;code&gt;events.bin.zst&lt;/code&gt;, implying zstd (&lt;a href=&quot;https://facebook.github.io/zstd/&quot;&gt;Zstandard&lt;/a&gt;) compression. This is obviously good! If you have a long-running and verbose build that dumps a ton of output to stdout and stderr, compression can save a lot of disk space.&lt;/p&gt;
&lt;p&gt;...but, I wanted to have my cake and eat it too. The new &lt;code&gt;brioche jobs logs&lt;/code&gt; command also supports the flag &lt;code&gt;--reverse&lt;/code&gt;, allowing you to print events starting from the end. For a super long build log, it&apos;d be annoying to have to wait for the entire file to decompress just to show the last 100 or so log lines!&lt;/p&gt;
&lt;p&gt;That&apos;s when I learned about the &lt;a href=&quot;https://github.com/facebook/zstd/tree/45fdc5f9e408f41f10e671c207cd424b20ce58f3/contrib/seekable_format&quot;&gt;zstd seekable format&lt;/a&gt;, which basically chunks a zstd stream into multiple frames, and allows efficient seeking by only needing to decompress a particular frame: in the case of reading only a few lines starting from the end, you might only need to read the last frame for example (currently ~1MB of data). It&apos;s not a magic bullet though: dividing a stream into multiple frames does harm the compression ratio. But, in this case, I thought the trade-off was worth it.&lt;/p&gt;
&lt;p&gt;Unfortunately, the zstd seekable format isn&apos;t yet supported in either the &lt;code&gt;zstd&lt;/code&gt; or the &lt;code&gt;async-compression&lt;/code&gt; Rust crates (it &lt;em&gt;should&lt;/em&gt; be decodable by any compliant decoder, but it wouldn&apos;t allow seeking and it wouldn&apos;t be possible to encode the seekable format without explicit support). So, I ended up writing the &lt;a href=&quot;https://crates.io/crates/zstd-framed&quot;&gt;&lt;code&gt;zstd-framed&lt;/code&gt;&lt;/a&gt; crate to handle the compression and decompression with the seekable format. It should also gracefully handle edge cases, like if the process dies after having written a partial file, where it&apos;ll allow decoding even if the file wasn&apos;t closed properly during encoding. Good if, I dunno, your computer shuts down during a long-running build!&lt;/p&gt;
&lt;p&gt;Anyway, the choice to use compression ended up stretching out development of the new process event format by several weeks, but I&apos;m really happy with the end result!&lt;/p&gt;
&lt;h2&gt;Extension updates&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt; just published v0.2.0 of the &lt;code&gt;brioche-vscode&lt;/code&gt; extension, and added a new GitHub Actions workflow to simplify publishing of future versions! The new release doesn&apos;t have any feature changes, but bumps the versions of various dependencies (and additionally now requires a newer version of VS Code, hence why it was a bump to v0.2.0).&lt;/p&gt;
&lt;p&gt;Also, we published the VS Code extension in the &lt;a href=&quot;https://open-vsx.org/extension/brioche-dev/brioche-vscode&quot;&gt;Open VSX Registry&lt;/a&gt; (although at the time of writing, our namespace is not yet verified, track &lt;a href=&quot;https://github.com/EclipseFdn/open-vsx.org/issues/3124&quot;&gt;this issue&lt;/a&gt; for progress). This means you can now use Brioche in other VS Code-based editors, such as &lt;a href=&quot;https://vscodium.com/&quot;&gt;VSCodium&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Infrastructure updates&lt;/h2&gt;
&lt;p&gt;In our homelab, we have an M1 Mac mini that has gone largely unused since we got it. I finally decided to provision it with &lt;a href=&quot;https://asahilinux.org/&quot;&gt;Asahi Linux&lt;/a&gt;, which means I now have a powerful machine for doing native ARM64 Linux builds locally! This represents the first tangible work towards getting Brioche supporting cross-platform builds-- first up will be supporting &lt;em&gt;native&lt;/em&gt; ARM64 (aarch64) Linux builds, followed by supporting ARM64-to-x86_64 and x86_64-to-ARM64 cross builds. The Asahi-ified Mac mini will be how I&apos;ll work on builds, and it&apos;ll eventually become a GitHub Actions runner for the &lt;code&gt;brioche-packages&lt;/code&gt; repo.&lt;/p&gt;
&lt;h2&gt;Coming soon&lt;/h2&gt;
&lt;p&gt;Here&apos;s my shortlist of features that I&apos;m semi-planning to work on soon:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMake!&lt;/li&gt;
&lt;li&gt;More work on improving the flow when debugging failed builds, including:
&lt;ul&gt;
&lt;li&gt;Different build ID format (we currently use ULID, which turns out to be counter-productive as it takes a lot of characters to disambiguate failed builds)&lt;/li&gt;
&lt;li&gt;Command to show failed builds without using a full path, e.g. &lt;code&gt;brioche jobs logs $BUILD_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Record failed builds in Brioche database, so we can easily clean old failed builds and to allow e.g. &lt;code&gt;brioche jobs logs last&lt;/code&gt; to show the last failed build&lt;/li&gt;
&lt;li&gt;Allow for starting a shell within a failed build to allow for debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Look for low-hanging fruit to speed up build times. &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/78&quot;&gt;brioche-dev/brioche#78&lt;/a&gt; is the first candidate here&lt;/li&gt;
&lt;li&gt;Make some progress on ARM64 Linux toolchain builds&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - October 2024</title><link>https://brioche.dev/blog/project-update-2024-10</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2024-10</guid><pubDate>Sat, 05 Oct 2024 05:17:40 GMT</pubDate><content:encoded>&lt;p&gt;Well, it&apos;s been a busy couple of months! Since the &lt;a href=&quot;/blog/project-update-2024-08&quot;&gt;last update in August&lt;/a&gt;, there have been &lt;em&gt;two&lt;/em&gt; releases, some big changes in &lt;code&gt;std&lt;/code&gt;, and more!&lt;/p&gt;
&lt;h2&gt;Blog posts&lt;/h2&gt;
&lt;p&gt;If you hadn&apos;t seen it yet, I published a post a couple of weeks ago called &lt;a href=&quot;/blog/portable-dynamically-linked-packages-on-linux&quot;&gt;&quot;Portable, dynamically linked packages on Linux&quot;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s a pretty in-depth behind the scenes look at how &lt;a href=&quot;/docs/how-it-works/packed-executables&quot;&gt;packed executables&lt;/a&gt; work in Brioche. I wanted to make it general enough that folks interested in packaging or distributing software more generally for Linux get some value out of it-- which is also why it&apos;s pretty technical and long&lt;/p&gt;
&lt;h2&gt;Brioche releases&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.2&quot;&gt;Brioche v0.1.2&lt;/a&gt; was released last week, with &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.3&quot;&gt;Brioche v0.1.3&lt;/a&gt; close behind. v0.1.3 was pretty small release with a few bugfixes (most notably a fix for an LSP regression from v0.1.2), but the real meat and potatoes were in v0.1.2.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/brioche-dev/brioche/releases/tag/v0.1.2&quot;&gt;release notes&lt;/a&gt; cover everything that changed, and there&apos;s a lot of exciting stuff! Especially the CLI changes that allow for running across multiple projects at once and the fix for the Brioche auto-updater (finally!) which will make future updates go more smoothly.&lt;/p&gt;
&lt;p&gt;My favorite new features though are locked downloads and locked git refs.&lt;/p&gt;
&lt;h3&gt;Locked downloads&lt;/h3&gt;
&lt;p&gt;Up to this point, if you were adding a package in Brioche, you&apos;d get something that looks like &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/79f173c68d3e2db6b51f70ad6cc246706df659dc/packages/dust/project.bri&quot;&gt;this package (dust)&lt;/a&gt;. In the middle, you&apos;d see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const source = std
  .download({
    url: `https://github.com/bootandy/dust/archive/refs/tags/v${project.version}.tar.gz`,
    hash: std.sha256Hash(
      &quot;98cae3e4b32514e51fcc1ed07fdbe6929d4b80942925348cc6e57b308d9c4cb0&quot;,
      // ^^^ tedious, boring busywork ^^^
    ),
  })
  .unarchive(&quot;tar&quot;, &quot;gzip&quot;)
  .peel();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To download the source code to build a project, we need its hash. So, how do we even &lt;em&gt;get&lt;/em&gt; the hash for a URL? Well, before v0.1.2, there were two ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copy the URL and paste it into a shell one-liner using &lt;code&gt;curl | sha256sum&lt;/code&gt;, then copy the hash into the source code&lt;/li&gt;
&lt;li&gt;Add an invalid hash, run the build, then copy the hash from the error message into the source code&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In either case, &lt;em&gt;manually&lt;/em&gt; copy/pasting hashes is busywork, which is the kind of thing we want to automate away. Which brings us to &lt;code&gt;Brioche.download&lt;/code&gt;! Here&apos;s a snippet that&apos;s roughly the same as before:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const source = Brioche.download(
  `https://github.com/bootandy/dust/archive/refs/tags/v${project.version}.tar.gz`,
  // No more hash!
)
  .unarchive(&quot;tar&quot;, &quot;gzip&quot;)
  .peel();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &quot;trick&quot; is that, when you call &lt;code&gt;brioche build&lt;/code&gt; on this project, Brioche scans for all occurrences of &lt;code&gt;Brioche.download&lt;/code&gt; in the code, downloads each one, then &lt;em&gt;saves each hash in the lockfile&lt;/em&gt;. This has all the same benefits as having the hash directly in the source code, except you don&apos;t need to manually figure out the hash yourself (plus Brioche only downloads the URL once, instead of making Brioche download it a second time after you manually hashed it)&lt;/p&gt;
&lt;p&gt;Since Brioche needs to scan the script to find all URLs, there are some limitations on how you can construct the URL. Namely, the URL needs to be hard-coded as a string literal, or as a template that uses the &lt;a href=&quot;/docs/core-concepts/projects/#project-metadata&quot;&gt;project metadata&lt;/a&gt; (like &lt;code&gt;project.version&lt;/code&gt; above). In the future, it should be possible to make this support a little more general, but the important thing is that Brioche needs to be able to figure out the URL &lt;em&gt;statically&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Locked git refs&lt;/h3&gt;
&lt;p&gt;In the same vein, packages that clone from git &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/79f173c68d3e2db6b51f70ad6cc246706df659dc/packages/gitui/project.bri&quot;&gt;used to need to reference the git hash directly in the source code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you squint, this is the exact same problem as with URL download hashes! So, Brioche can also apply the same trick: instead of referencing the git hash directly, you can call &lt;code&gt;Brioche.gitRef({ repository, ref })&lt;/code&gt;, and Brioche will record the commit hash the currently corresponds with that git ref in the lockfile, such as in this snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Previously
// const source = gitCheckout({
//   repository: &quot;https://github.com/extrawurst/gitui.git&quot;,
//   commit: &quot;95e1d4d4324bf1eab34f8100afc7f3ae7e435252&quot;,
//   // Commit grabbed manually by finding the right tag in the repo
// });

// Now
const source = gitCheckout(
  Brioche.gitRef({
    repository: &quot;https://github.com/extrawurst/gitui.git&quot;,
    ref: `v${project.version}`,
    // The commit hash for the version tag gets saved in the lockfile
  }),
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Package updates&lt;/h2&gt;
&lt;p&gt;Since the last update, the only new package is &lt;code&gt;terraform&lt;/code&gt; (thanks &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!), but quite a few packages were also updated across the board (kudos to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;rust&lt;/code&gt; package was updated from v1.79 to v1.81, which did see a few packages break along the way. &lt;code&gt;go&lt;/code&gt; was also updated to support more complex module layouts, namely to unblock the &lt;code&gt;terraform&lt;/code&gt; package (under the hood, the &lt;code&gt;go&lt;/code&gt; package now properly grabs all the &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; files before trying to download dependencies).&lt;/p&gt;
&lt;h2&gt;std updates&lt;/h2&gt;
&lt;p&gt;A &lt;em&gt;lot&lt;/em&gt; of work went into &lt;code&gt;std&lt;/code&gt; updates. The &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/e70bd2a3525e6b7b3603cd3aa9a3e047d59d8b4f/packages/std/CHANGELOG.md#2024-10-04&quot;&gt;changelog&lt;/a&gt; has a full breakdown.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;std.glob()&lt;/code&gt;, &lt;code&gt;Brioche.download()&lt;/code&gt;, and &lt;code&gt;Brioche.gitRef()&lt;/code&gt; functions were added to support new features from Brioche v0.1.2. The &lt;code&gt;std.setEnv()&lt;/code&gt; function had a breaking change that also enables support for more ways to set env vars (which also requires Brioche v0.1.2). Also, the new &lt;code&gt;std.semverMatches()&lt;/code&gt; function allows for testing semver constraints, which is used by &lt;code&gt;std&lt;/code&gt; itself to ensure you can&apos;t accidentally use new features on older versions of Brioche&lt;/p&gt;
&lt;p&gt;&lt;code&gt;std.toolchain()&lt;/code&gt; now sets a bunch of env vars that autotools use, so autotools builds should now work &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/110/files#diff-caf738b3d91954f00137e92a4503a1fb820a9faa08722f37f64a4b7f1689b2bc&quot;&gt;without needing to configure lots of env vars manually!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Also, both &lt;code&gt;std.toolchain()&lt;/code&gt; and &lt;code&gt;std.tools()&lt;/code&gt; are now &quot;rewrapped&quot;, which ensures the final built version of glibc is used internally by all the different binaries. Previously, if you saved &lt;code&gt;std.toolchain()&lt;/code&gt; as an output, you&apos;d see that there were multiple different copies of glibc present in the output, due to different binaries being built at different stages and ending up with different versions of glibc! Rewrapping ensures everything is using a single copy of glibc for consistency (which also has the nice benefit that the output is now smaller too!)&lt;/p&gt;
&lt;h2&gt;Brioche core updates&lt;/h2&gt;
&lt;p&gt;Shortly after the v0.1.3 update, I fixed another LSP issue (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/134&quot;&gt;#134&lt;/a&gt;). This one is certainly annoying as well, but I didn&apos;t feel that it was critical enough to cut another release immediately.&lt;/p&gt;
&lt;p&gt;I also added a new &lt;code&gt;--locked&lt;/code&gt; flag for the quartet of &lt;code&gt;brioche build&lt;/code&gt;, &lt;code&gt;brioche run&lt;/code&gt;, &lt;code&gt;brioche check&lt;/code&gt; and &lt;code&gt;brioche install&lt;/code&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/133&quot;&gt;#133&lt;/a&gt;). Basically, it just ensures that the &lt;code&gt;brioche.lock&lt;/code&gt; lockfile is up-to-date. This is useful for CI/CD (and was also sorely needed for the &lt;code&gt;brioche-packages&lt;/code&gt; repo, especially now that downloads and git refs are being recorded in the lockfile)&lt;/p&gt;
&lt;h2&gt;Infrastructure updates&lt;/h2&gt;
&lt;p&gt;I&apos;ve been doing my best running Brioche &lt;a href=&quot;https://brioche.zulipchat.com/#narrow/stream/440653-general/topic/Storage.20size.20information/near/459742418&quot;&gt;on a shoestring budget&lt;/a&gt;, and so far things have been going really well! Besides an &lt;a href=&quot;https://community.fly.io/t/tls-handshake-failing-on-fly-io-app/21923/3&quot;&gt;outage due to an expired TLS cert&lt;/a&gt;, all of the infrastructure behind Brioche has been ticking along smoothly.&lt;/p&gt;
&lt;p&gt;...well, with one exception. Builds are obviously &lt;em&gt;super&lt;/em&gt; important for Brioche, and making it so updates to the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages&quot;&gt;&lt;code&gt;brioche-packages&lt;/code&gt;&lt;/a&gt; repo get built and published in a timely manner is a core part of the project!&lt;/p&gt;
&lt;p&gt;That entire pipeline is handled with a &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/fe61cd9719c661267dc843548899df37b0b49cef/.github/workflows/ci.yml&quot;&gt;pretty boring GitHub Actions workflow&lt;/a&gt;, which first validates all the packages, builds and syncs the recipes to the registry, then publishes the project files to the recipe. We use GitHub Action&apos;s generous free runners where possible. But, for the actual slow, CPU-intensive builds, those get run on my and &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;&apos;s homelab.&lt;/p&gt;
&lt;p&gt;In early September, I decided to upgrade the Linux kernel on the hypervisor, plus all of the OS packages. The upgrade &lt;em&gt;appeared&lt;/em&gt; to go fine. It was not fine.&lt;/p&gt;
&lt;p&gt;To cut a long story short, the server would crash after about 24 hours of uptime (and, very annoyingly, would bring down our entire home network as well). We fought for &lt;em&gt;weeks&lt;/em&gt; to triage the issue, from using older kernel releases, to trying out different kernel flags, to swapping the NIC in the server (which at least made it so the server crashes wouldn&apos;t bring down the network), to updating the BIOS. The last thing we did was disabling CPU C-states in the BIOS, and so far that seems to be holding strong&lt;/p&gt;
&lt;h2&gt;Coming soon&lt;/h2&gt;
&lt;p&gt;As with last time, here&apos;s a short wishlist of things I hope to make progress on soon&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMake and Python are still work in progress and haven&apos;t been touched since the last update. These will be pretty high priority!&lt;/li&gt;
&lt;li&gt;There&apos;s still some work to do before merging &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/80&quot;&gt;brioche-dev/brioche-packages#80&lt;/a&gt;, but that should unlock more NPM packages as well&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Brioche.download()&lt;/code&gt; and &lt;code&gt;Brioche.gitRef()&lt;/code&gt; make it so many package updates are as simple as bumping a version number in &lt;code&gt;project.bri&lt;/code&gt;. The next logical step would be to support package auto-updates, where bumping the version number itself is automated&lt;/li&gt;
&lt;li&gt;Still no forward progress on cross-platform support. The immediate next step is to set up Asahi Linux on our homelab Mac Mini, which will make it possible to start tinkering with ARM64 Linux builds&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Portable, dynamically linked packages on Linux</title><link>https://brioche.dev/blog/portable-dynamically-linked-packages-on-linux</link><guid isPermaLink="true">https://brioche.dev/blog/portable-dynamically-linked-packages-on-linux</guid><pubDate>Sun, 22 Sep 2024 00:46:12 GMT</pubDate><content:encoded>&lt;p&gt;Hey, want to see a magic trick? If you &lt;a href=&quot;https://brioche.dev/docs/installation/&quot;&gt;have Brioche installed&lt;/a&gt;, you can run this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brioche build curl -o ./output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...to get a copy of curl! Like you can then run &lt;code&gt;./output/bin/curl --version&lt;/code&gt; and it works!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;*crickets*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Okay, not impressed? Well, like all of the best magicians, I will now explain why this is a good trick:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;output&lt;/code&gt; directory contains every file we need to run curl&lt;/li&gt;
&lt;li&gt;The underlying curl binary is dynamically linked against glibc&lt;/li&gt;
&lt;li&gt;There are no containers up my sleeve[^the-container-up-my-sleeve-kinda]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Which means we can just put this directory &lt;em&gt;anywhere on the file system&lt;/em&gt; and it&apos;ll run... including in a container image. Presto, behold a &lt;code&gt;Dockerfile&lt;/code&gt;!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM scratch
COPY output /output
ENTRYPOINT [ &quot;/output/bin/curl&quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save it as &lt;code&gt;Dockerfile&lt;/code&gt; (or &lt;code&gt;Containerfile&lt;/code&gt;), build it with Podman / Docker / etc, and it still runs, even in the completely barren &lt;a href=&quot;https://hub.docker.com/_/scratch&quot;&gt;&lt;code&gt;scratch&lt;/code&gt;&lt;/a&gt; environment:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ podman build . -t magic-trick
$ podman run --rm magic-trick --version
curl 8.8.0 (x86_64-pc-linux-gnu) libcurl/8.8.0 OpenSSL/3.3.1 zlib/1.2.13 zstd/1.5.5
Release-Date: 2024-05-22
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS HSTS HTTPS-proxy IPv6 Largefile libz NTLM SSL threadsafe TLS-SRP UnixSockets zstd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not just that, but the container we get out is actually pretty small[^small-container], since it&apos;s &lt;a href=&quot;https://github.com/GoogleContainerTools/distroless&quot;&gt;distroless&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;so? who cares??&lt;/h2&gt;
&lt;p&gt;Well, I care, for one! I&apos;m a weirdo trying to build a package manager. And building a package manager means... putting packages on people&apos;s computers, so you need to figure out &lt;em&gt;where&lt;/em&gt; to put the package on the computer. Being able to put the package &lt;em&gt;anywhere&lt;/em&gt; makes it easier!&lt;/p&gt;
&lt;p&gt;Let&apos;s look at those those 3 facts about this version of curl from before:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;output&lt;/code&gt; directory contains every file we need to run curl&lt;/li&gt;
&lt;li&gt;The underlying curl binary is dynamically linked against glibc&lt;/li&gt;
&lt;li&gt;There are no containers here&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Depending on how much you know about dynamic linking, it should seem impossible for all 3 of these things to be true. Let&apos;s ignore the how for now and talk about &lt;strong&gt;why I made it work this way&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You shouldn&apos;t need root permissions to install Brioche or to install new packages&lt;/strong&gt;. Package managers usually install packages into a global, fixed directory (&lt;code&gt;/nix&lt;/code&gt; for Nix, &lt;code&gt;/home/linuxbrew/.linuxbrew&lt;/code&gt; for Homebrew), but that&apos;s just not an option if we want everything to work rootlessly. So we need to make everything portable so it works from anywhere on the filesystem&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brioche should be able to package software that uses glibc&lt;/strong&gt;. The obvious option would be to just use musl libc for everything, which makes it easier to do fully static builds. The problem is musl isn&apos;t a drop-in replacement for glibc: as an example, &lt;a href=&quot;https://purplecarrot.co.uk/post/2021-09-04-does_alpine-resolve_dns_properly/&quot;&gt;musl&apos;s DNS resolution trips people up&lt;/a&gt;. I really wanted to support packages that wanted or needed to use glibc (&lt;strong&gt;Update&lt;/strong&gt;: &lt;strong&gt;ifreund&lt;/strong&gt; &lt;a href=&quot;https://lobste.rs/s/gyiims/portable_dynamically_linked_packages_on#c_edqv6f&quot;&gt;pointed out&lt;/a&gt; that musl now supports TCP DNS fallback! There are still &lt;a href=&quot;https://wiki.musl-libc.org/functional-differences-from-glibc.html&quot;&gt;differences from glibc&lt;/a&gt;, so it still won&apos;t work for programs that depend on glibc-specific behavior)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brioche packages shouldn&apos;t use containers at runtime&lt;/strong&gt;. &lt;a href=&quot;https://snapcraft.io/&quot;&gt;snap&lt;/a&gt;, &lt;a href=&quot;https://flatpak.org/&quot;&gt;Flatpak&lt;/a&gt;, and &lt;a href=&quot;https://appimage.org/&quot;&gt;AppImage&lt;/a&gt; all already use containers for packages, but I wanted to kick Brioche off with a focus on developer-facing CLI tools-- things that would be more awkward to try and use from a containerized environment. Since containers have their own view of the filesystem, using tools like &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;du&lt;/code&gt;, etc. might not work like you expect! Plus, containers are a form of sandboxing and sandboxing is hard and I didn&apos;t want &quot;solving sandboxing&quot; to be a yak I needed to shave as a precursor[^sandboxing-future]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So hopefully you can see how the little party trick with curl came to be: to tick all the boxes for Brioche, I &lt;em&gt;had&lt;/em&gt; to make that trick work. Every package in Brioche works this way, too. You can just put any package into a directory somewhere on your filesystem, and it&apos;ll run entirely self-contained even for a completely bare-bones Linux setup&lt;/p&gt;
&lt;h2&gt;Let&apos;s do it ourselves&lt;/h2&gt;
&lt;p&gt;So let&apos;s make our own portable package that checks all the same boxes that we get from Brioche. Let&apos;s start with a little Rust program to use as our candidate to package. First, run &lt;code&gt;cargo new lil-demo&lt;/code&gt;, then &lt;code&gt;cd lil-demo&lt;/code&gt;, then put this in &lt;code&gt;src/main.rs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// lil-demo/src/main.rs
fn main() {
    let location = std::env::current_exe().unwrap();
    println!(&quot;Hello from {}&quot;, location.display());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a program calls &lt;a href=&quot;https://doc.rust-lang.org/stable/std/env/fn.current_exe.html&quot;&gt;&lt;code&gt;std::env::current_exe()&lt;/code&gt;&lt;/a&gt;, it gets the path to itself (yes, using this particular function is important, we&apos;ll come back to it later). If you run it with &lt;code&gt;cargo run&lt;/code&gt;, you&apos;ll see some output like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello from /your/path/to/lil-demo/target/debug/lil-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait, actually, I should mention... I&apos;m in an Ubuntu Linux environment, so by default Cargo dynamically links my &lt;code&gt;lil-demo&lt;/code&gt; program against glibc. This is true for most Linux distros, but if yours is different, you might not be able to follow along.&lt;/p&gt;
&lt;h3&gt;Finding all the dependencies&lt;/h3&gt;
&lt;p&gt;So we want to package our &lt;code&gt;lil-demo&lt;/code&gt; up just like we had curl at the start. Remember, that means &lt;strong&gt;we need to put all of its dependencies into a self-contained directory&lt;/strong&gt;. So, what does it depend on? Well, we can answer that using &lt;code&gt;ldd&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ldd target/debug/lil-demo
linux-vdso.so.1 (0x00007ffd6c14a000)
libgcc_s.so.1 =&amp;gt; /home/linuxbrew/.linuxbrew/lib/libgcc_s.so.1 (0x00007fa6b1856000)
libc.so.6 =&amp;gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa6b1620000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa6b18d2000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each line is a dynamic library our &lt;code&gt;lil-demo&lt;/code&gt; depends on, which shows the name of the library that the program asked for, then the location it actually loaded it from (the hex is the address it got loaded to but we don&apos;t care about that):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;linux-vdso.so.1&lt;/code&gt;: Okay, we start off with a free square! The &lt;a href=&quot;https://man7.org/linux/man-pages/man7/vdso.7.html&quot;&gt;&quot;vDSO&quot;&lt;/a&gt; is a special dynamic library provided by the Linux kernel itself, so it&apos;s not our responsibility to provide it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libgcc_s.so.1&lt;/code&gt;: Provided by gcc, and I think Rust links against it for stack traces or something. It&apos;s a very common standard system library (don&apos;t ask why mine comes from Homebrew)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libc.so.6&lt;/code&gt;: The main C library, glibc in my case. This is another system library&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/lib64/ld-linux-x86-64.so.2&lt;/code&gt;: Okay, this one&apos;s pretty complicated. This is the &lt;a href=&quot;https://man7.org/linux/man-pages/man8/ld-linux.so.8.html&quot;&gt;dynamic linker&lt;/a&gt;. When you try to run &lt;code&gt;lil-demo&lt;/code&gt;, the Linux kernel &lt;em&gt;actually&lt;/em&gt; calls this &lt;code&gt;ld-linux-x86-64.so.2&lt;/code&gt; program instead (because its dynamically linked). It&apos;s job is to first find all the dynamic libraries &lt;code&gt;lil-demo&lt;/code&gt; needs, load them into memory, then &lt;em&gt;really&lt;/em&gt; run &lt;code&gt;lil-demo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you might&apos;ve guessed, the name of that last one in particular varies per platform, so I&apos;m going to use the generic name of &lt;code&gt;ld-linux.so&lt;/code&gt; when I talk about it instead.&lt;/p&gt;
&lt;h3&gt;Setting up the portable directory&lt;/h3&gt;
&lt;p&gt;So in total, we need the &lt;code&gt;lil-demo&lt;/code&gt; program itself, the 2 dynamic libraries it links against (not counting the &quot;vDSO&quot; one Linux gives us for free), and &lt;code&gt;ld-linux.so&lt;/code&gt;, a.k.a. the dynamic linker. How do we combine these ingredients to make something portable?&lt;/p&gt;
&lt;p&gt;Let&apos;s start with a little boilerplate first:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make a new directory: &lt;code&gt;mkdir lil-demo-portable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Copy &lt;code&gt;lil-demo&lt;/code&gt; into it: &lt;code&gt;cp target/debug/lil-demo lil-demo-portable/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Copy the 2 dynamic libraries and &lt;code&gt;ld-linux.so&lt;/code&gt; into it too. These will be whatever paths you got from &lt;code&gt;ldd&lt;/code&gt;. In other words, something like &lt;code&gt;cp /path/to/libgcc_s.so.1 /path/to/libc.so.6 /lib64/ld-linux-x86-64.so.2 ./lil-demo-portable/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a new shell script at &lt;code&gt;lil-demo-portable/run.sh&lt;/code&gt; with the following contents:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# lil-demo/lil-demo-portable/run.sh
#!/usr/bin/env bash

portable_dir=$(cd -- &quot;$(dirname -- &quot;${BASH_SOURCE[0]}&quot;)&quot; &amp;amp;&amp;gt; /dev/null &amp;amp;&amp;amp; pwd)

exec &quot;$portable_dir&quot;/lil-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, mark the script as executable and run it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ chmod +x lil-demo-portable/run.sh
$ ./lil-demo-portable/run.sh
Hello from /your/path/to/lil-demo/lil-demo-portable/lil-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, so the script is pretty straightforward: first, it &lt;a href=&quot;https://stackoverflow.com/a/246128&quot;&gt;gets the directory containing the shell script itself&lt;/a&gt; (meaning &lt;code&gt;lil-demo-portable/&lt;/code&gt;). Then, it uses &lt;code&gt;exec&lt;/code&gt; to run the original &lt;code&gt;lil-demo&lt;/code&gt; binary that we copied in[^exec]. Unsurprisingly, we see the path of this copied binary!&lt;/p&gt;
&lt;p&gt;Okay, we&apos;ve finally set the stage to actually make &lt;code&gt;lil-demo&lt;/code&gt; into a lil&apos; &lt;em&gt;portable&lt;/em&gt; demo&lt;/p&gt;
&lt;h3&gt;Wrapping the binary&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;lil-demo&lt;/code&gt; runs, we want it to use the copied libraries from within &lt;code&gt;lil-demo-portable&lt;/code&gt;. The easiest way is to set the env var &lt;code&gt;$LD_LIBRARY_PATH&lt;/code&gt;. When it&apos;s set, &lt;code&gt;ld-linux.so&lt;/code&gt; uses it as a place to find dynamic libraries, which is exactly what we want! Here&apos;s an updated &lt;code&gt;run.sh&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# lil-demo/lil-demo-portable/run.sh
#!/usr/bin/env bash

portable_dir=$(cd -- &quot;$(dirname -- &quot;${BASH_SOURCE[0]}&quot;)&quot; &amp;amp;&amp;gt; /dev/null &amp;amp;&amp;amp; pwd)
export LD_LIBRARY_PATH=&quot;$portable_dir&quot;

exec &quot;$portable_dir&quot;/lil-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...basically, we just set &lt;code&gt;$LD_LIBRARY_PATH&lt;/code&gt; to the directory containing the shell script itself. If we run &lt;code&gt;run.sh&lt;/code&gt; again, the result is the same. But now, all the dynamic libraries get read directly from the &lt;code&gt;lil-demo-portable-dir&lt;/code&gt;! Neat!&lt;/p&gt;
&lt;p&gt;(If you want to see for yourself that libraries are now getting resolved correctly, change the last line of &lt;code&gt;run.sh&lt;/code&gt; to &lt;code&gt;ldd &quot;$portable_dir&quot;/lil-demo&lt;/code&gt;)&lt;/p&gt;
&lt;h3&gt;Wrapping the dynamic linker, too&lt;/h3&gt;
&lt;p&gt;So we&apos;re running &lt;code&gt;lil-demo&lt;/code&gt; from our portable directory, and we&apos;re even loading all the dynamic libraries we need from it to thanks to &lt;code&gt;$LD_LIBRARY_PATH&lt;/code&gt;. That just leaves &lt;code&gt;ld-linux.so&lt;/code&gt;. To recap, it&apos;s not a dynamic library itself, but it&apos;s the thing responsible for loading all the dynamic libraries.&lt;/p&gt;
&lt;p&gt;When we run &lt;code&gt;lil-demo&lt;/code&gt; (either directly or via &lt;code&gt;run.sh&lt;/code&gt;), the Linux kernel doesn&apos;t actually run &lt;code&gt;lil-demo&lt;/code&gt; directly. Instead, it checks the header of the file-- specifically, the &lt;code&gt;PT_INTERP&lt;/code&gt; element from the program header of the ELF file-- sees that it points to &lt;code&gt;/lib64/ld-linux-x86-64.so.2&lt;/code&gt;, and runs that instead.&lt;/p&gt;
&lt;p&gt;In other words, this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./lil-demo-portable/lil-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...effectively becomes this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ /lib64/ld-linux-x86-64.so.2 ./lil-demo-portable/lil-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we don&apos;t want it to become that! We &lt;em&gt;want&lt;/em&gt; it to call the &lt;code&gt;ld-linux.so&lt;/code&gt; that&apos;s under &lt;code&gt;lil-demo-portable&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;...so instead, we can just call &lt;code&gt;ld-linux.so&lt;/code&gt; directly ourselves. Here&apos;s an updated &lt;code&gt;run.sh&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# lil-demo/lil-demo-portable/run.sh
#!/usr/bin/env bash

portable_dir=$(cd -- &quot;$(dirname -- &quot;${BASH_SOURCE[0]}&quot;)&quot; &amp;amp;&amp;gt; /dev/null &amp;amp;&amp;amp; pwd)
export LD_LIBRARY_PATH=&quot;$portable_dir&quot;

exec &quot;$portable_dir&quot;/ld-linux-x86-64.so.2 &quot;$portable_dir&quot;/lil-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We just changed the last line to execute &lt;code&gt;ld-linux.so&lt;/code&gt; with &lt;code&gt;lil-demo&lt;/code&gt; as an argument. And, we can run it and see it works just like before, just using our copy of &lt;code&gt;ld-linux.so&lt;/code&gt; from the portable directory instead!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./lil-demo-portable/run.sh
Hello from /your/path/to/lil-demo/lil-demo-portable/ld-linux-x86-64.so.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;...wait, something feels... off somehow? Do you feel it? Let&apos;s zoom and enhance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-Hello from /your/path/to/lil-demo/lil-demo-portable/lil-demo
+Hello from /your/path/to/lil-demo/lil-demo-portable/ld-linux-x86-64.so.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...the path changed from &lt;code&gt;lil-demo&lt;/code&gt; to &lt;code&gt;ld-linux.so&lt;/code&gt;???&lt;/p&gt;
&lt;h3&gt;Checkov&apos;s path&lt;/h3&gt;
&lt;p&gt;Okay, remember a million words ago when I said &lt;a href=&quot;https://doc.rust-lang.org/stable/std/env/fn.current_exe.html&quot;&gt;&lt;code&gt;std::env::current_exe()&lt;/code&gt;&lt;/a&gt; was going to be important later? Well later is now, and now we need to talk about it&lt;/p&gt;
&lt;p&gt;How does &lt;code&gt;lil-demo&lt;/code&gt; know where it is? &lt;s&gt;it knows where it is because it knows where it isn&apos;t&lt;/s&gt; it knows where it is because it reads the path of the symlink &lt;code&gt;/proc/self/exe&lt;/code&gt;[^proc-absolute-path], which is a special symlink that Linux sets up that &lt;em&gt;always refers to the current executable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For a demo that&apos;s kinda trippy, try this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ readlink /proc/self/exe
/usr/bin/readlink
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When &lt;code&gt;readlink&lt;/code&gt; reads the &lt;code&gt;/proc/self/exe&lt;/code&gt; symlink, then &lt;em&gt;by definition&lt;/em&gt;, it reads its own path, so it prints the path to &lt;code&gt;readlink&lt;/code&gt; itself!&lt;/p&gt;
&lt;p&gt;And of course, that&apos;s also exactly how &lt;a href=&quot;https://doc.rust-lang.org/stable/std/env/fn.current_exe.html&quot;&gt;&lt;code&gt;std::env::current_exe()&lt;/code&gt;&lt;/a&gt; is implemented&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;/proc/self/exe&lt;/code&gt; is some Weird Magic that gets controlled by the Linux kernel. It basically points to whatever file was passed to the underlying &lt;a href=&quot;https://man7.org/linux/man-pages/man2/execve.2.html&quot;&gt;&lt;code&gt;execve()&lt;/code&gt; syscall&lt;/a&gt;. Our shell script is now executing &lt;code&gt;ld-linux.so&lt;/code&gt; instead of &lt;code&gt;lil-demo&lt;/code&gt;, so that&apos;s what &lt;code&gt;/proc/self/exe&lt;/code&gt; resolves to. And &lt;code&gt;ld-linux.so&lt;/code&gt; then sets up and runs our program directly (i.e. no calls to &lt;code&gt;execve()&lt;/code&gt;), so &lt;code&gt;/proc/self/exe&lt;/code&gt; is &quot;stuck&quot; with &lt;code&gt;ld-linux.so&lt;/code&gt; until the process ends or until it uses the &lt;code&gt;execve()&lt;/code&gt; syscall itself&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Wait but why do we care so much about &lt;code&gt;/proc/self/exe&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You&apos;d be surprised how many programs will break if they don&apos;t get the right value for &lt;code&gt;/proc/self/exe&lt;/code&gt;! The Rust compiler itself reads &lt;code&gt;/proc/self/exe&lt;/code&gt; to resolve the path to the Rust standard library. Off the top of my head, I &lt;em&gt;believe&lt;/em&gt; both Node.js and gcc both read &lt;code&gt;/proc/self/exe&lt;/code&gt; for resolving resources. It&apos;s just a pretty common thing that programs built for Linux end up depending on.&lt;/p&gt;
&lt;h2&gt;Fixing &lt;code&gt;/proc/self/exe&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Okay, so we know &lt;code&gt;/proc/self/exe&lt;/code&gt; is important, and we know we&apos;re now &quot;breaking&quot; it, in a sense. Let&apos;s step through how we got here&lt;/p&gt;
&lt;p&gt;At first, we started with just calling &lt;code&gt;exec lil-demo&lt;/code&gt;. The flow basically worked like this:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg class=&quot;w-full&quot; viewBox=&quot;-0.5 -0.5 681 201&quot;&amp;gt;
&amp;lt;title&amp;gt;Flow through the original lil-demo wrapper&amp;lt;/title&amp;gt;
&amp;lt;desc&amp;gt;Your shell calls run.sh using execve, which in turn calls lil-demo using execve. Indirectly, the call to lil-demo uses PT_INTERP from the ELF header to find ld-linux.so, which then loads and executes lil-demo&amp;lt;/desc&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 w-[78px] h-px pt-10 ml-px&quot;&amp;gt;your shell&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 80 40 L 193.63 40&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; d=&quot;M 198.88 40 L 191.88 43.5 L 193.63 40 L 191.88 36.5 Z&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs  text-accent-600 dark:text-accent-200 font-mono size-px pt-5 ml-[138px]&quot;&amp;gt;execve()&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;200&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[201px]&quot;&amp;gt;run.sh&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 280 40 L 593.63 40&quot; fill=&quot;none&quot; stroke=&quot;rgb(0, 0, 0)&quot; stroke-miterlimit=&quot;10&quot; pointer-events=&quot;stroke&quot;/&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; d=&quot;M 598.88 40 L 591.88 43.5 L 593.63 40 L 591.88 36.5 Z&quot; fill=&quot;rgb(0, 0, 0)&quot; stroke=&quot;rgb(0, 0, 0)&quot; stroke-miterlimit=&quot;10&quot; pointer-events=&quot;all&quot;/&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 font-mono size-px pt-[21px] ml-[441px]&quot;&amp;gt;execve()&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 240 80 L 240 160 L 393.63 160&quot; stroke-miterlimit=&quot;10&quot; stroke-dasharray=&quot;8 8&quot; /&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; d=&quot;M 398.88 160 L 391.88 163.5 L 393.63 160 L 391.88 156.5 Z&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 size-px pt-[141px] ml-[321px]&quot;&amp;gt;
&amp;lt;div&amp;gt;
&amp;lt;div&amp;gt;ELF header&amp;lt;/div&amp;gt;
&amp;lt;div className=&quot;font-mono&quot;&amp;gt;PT_INTERP&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;400&quot; y=&quot;120&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-40 ml-[401px]&quot;&amp;gt;ld-linux.so&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 480 160 L 640 160 L 640 86.37&quot; stroke-miterlimit=&quot;10&quot; stroke-dasharray=&quot;8 8&quot; /&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; d=&quot;M 640 81.12 L 643.5 88.12 L 640 86.37 L 636.5 88.12 Z&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 whitespace-nowrap size-px pt-[144px] ml-[551px]&quot;&amp;gt;load and execute&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;600&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible text-left&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[601px]&quot;&amp;gt;lil-demo&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;The execution of &lt;code&gt;lil-demo&lt;/code&gt; was implicitly calling &lt;code&gt;ld-linux.so&lt;/code&gt; under the hood via the &lt;code&gt;PT_INTERP&lt;/code&gt; field from the ELF header.&lt;/p&gt;
&lt;p&gt;In our latest version, we changed it to &lt;em&gt;explicitly&lt;/em&gt; call &lt;code&gt;exec ld-linux.so&lt;/code&gt;, so we could use the dynamic linker from our portable bundle:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg class=&quot;w-full&quot; viewBox=&quot;-0.5 -0.5 681 82&quot;&amp;gt;
&amp;lt;title&amp;gt;Flow through the current lil-demo wrapper&amp;lt;/title&amp;gt;
&amp;lt;desc&amp;gt;Your shell calls run.sh using execve, which calls ld-linux.so using execve, which then loads and executes lil-demo&amp;lt;/desc&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 w-[78px] h-px pt-10 ml-px&quot;&amp;gt;your shell&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 80 40 L 193.63 40&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; d=&quot;M 198.88 40 L 191.88 43.5 L 193.63 40 L 191.88 36.5 Z&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 font-mono size-px pt-5 ml-[138px]&quot;&amp;gt;execve()&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;200&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[201px]&quot;&amp;gt;run.sh&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 280 40 L 393.63 40&quot; /&amp;gt;
&amp;lt;path class=&quot;fill-accent-600 stroke-accent-600 dark:fill-accent-200 dark:stroke-accent-200&quot; d=&quot;M 398.88 40 L 391.88 43.5 L 393.63 40 L 391.88 36.5 Z&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 font-mono pt-5 ml-[345px] size-px overflow-visible&quot;&amp;gt;execve()&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;400&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[401px]&quot;&amp;gt;ld-linux.so&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 480 40 L 593.63 40&quot; stroke-miterlimit=&quot;10&quot; stroke-dasharray=&quot;8 8&quot; /&amp;gt;
&amp;lt;path d=&quot;M 598.88 40 L 591.88 43.5 L 593.63 40 L 591.88 36.5 Z&quot; class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 whitespace-nowrap size-px pt-5 ml-[540px]&quot;&amp;gt;load and execute&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;600&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[601px]&quot;&amp;gt;lil-demo&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;As we discussed before, &lt;code&gt;/proc/self/exe&lt;/code&gt; is determined by the &lt;em&gt;last&lt;/em&gt; call to &lt;code&gt;execve()&lt;/code&gt;. And we can see the path &lt;code&gt;ld-linux.so&lt;/code&gt; → &lt;code&gt;lil-demo&lt;/code&gt; does not use &lt;code&gt;execve()&lt;/code&gt;. So if we want to un-break &lt;code&gt;/proc/self/exe&lt;/code&gt;, we need to change our &lt;code&gt;execve()&lt;/code&gt; calls! ...somehow&lt;/p&gt;
&lt;p&gt;Maybe we could somehow change &lt;code&gt;ld-linux.so&lt;/code&gt; itself? Like, if we could make it so the path &lt;code&gt;ld-linux.so&lt;/code&gt; → &lt;code&gt;lil-demo&lt;/code&gt; uses &lt;code&gt;execve()&lt;/code&gt;, that could fix our problem? But remember, any time anything uses &lt;code&gt;execve()&lt;/code&gt; to call &lt;code&gt;lil-demo&lt;/code&gt;, the Linux kernel itself will do the little &lt;code&gt;ld-linux.so&lt;/code&gt; → &lt;code&gt;lil-demo&lt;/code&gt; dance for us, so we can&apos;t do that...&lt;/p&gt;
&lt;p&gt;The actual fix we&apos;re going for is to change the &lt;code&gt;run.sh&lt;/code&gt; → &lt;code&gt;ld-linux.so&lt;/code&gt; path. Specifically, we&apos;re going to explicitly call &lt;code&gt;ld-linux.so&lt;/code&gt; &lt;em&gt;without&lt;/em&gt; using &lt;code&gt;execve()&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg class=&quot;w-full&quot; viewBox=&quot;-0.5 -0.5 681 82&quot;&amp;gt;
&amp;lt;title&amp;gt;Proposed lil-demo execution flow&amp;lt;/title&amp;gt;
&amp;lt;desc&amp;gt;Your shell calls run using execve, which then loads and executes ld-linux.so, which in turn loads and executes lil-demo&amp;lt;/desc&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 w-[78px] h-px pt-10 ml-px&quot;&amp;gt;your shell&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 80 40 L 193.63 40&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; d=&quot;M 198.88 40 L 191.88 43.5 L 193.63 40 L 191.88 36.5 Z&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 font-mono size-px pt-5 ml-[138px]&quot;&amp;gt;execve()&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;200&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[201px]&quot;&amp;gt;run&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 280 40 L 393.63 40&quot; stroke-miterlimit=&quot;10&quot; stroke-dasharray=&quot;8 8&quot; /&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; d=&quot;M 398.88 40 L 391.88 43.5 L 393.63 40 L 391.88 36.5 Z&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 whitespace-nowrap pt-5 ml-[340px] size-px overflow-visible&quot;&amp;gt;load and execute&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;400&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[401px]&quot;&amp;gt;ld-linux.so&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;path class=&quot;stroke-accent-600 fill-none dark:stroke-accent-200&quot; d=&quot;M 480 40 L 593.63 40&quot; stroke-miterlimit=&quot;10&quot; stroke-dasharray=&quot;8 8&quot; /&amp;gt;
&amp;lt;path d=&quot;M 598.88 40 L 591.88 43.5 L 593.63 40 L 591.88 36.5 Z&quot; class=&quot;stroke-accent-600 fill-accent-600 dark:stroke-accent-200 dark:fill-accent-200&quot; stroke-miterlimit=&quot;10&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-600 dark:text-accent-200 whitespace-nowrap size-px pt-5 ml-[540px]&quot;&amp;gt;load and execute&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect class=&quot;stroke-accent-600 fill-accent-900&quot; x=&quot;600&quot; y=&quot;0&quot; width=&quot;80&quot; height=&quot;80&quot; /&amp;gt;
&amp;lt;foreignObject class=&quot;size-full overflow-visible&quot;&amp;gt;
&amp;lt;div class=&quot;flex items-center justify-center text-center text-xs text-accent-200 font-mono w-[78px] h-px pt-10 ml-[601px]&quot;&amp;gt;lil-demo&amp;lt;/div&amp;gt;
&amp;lt;/foreignObject&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;So how do we execute &lt;code&gt;ld-linux.so&lt;/code&gt; without using &lt;code&gt;execve()&lt;/code&gt;? How can we execute something without using the special &quot;execute something&quot; syscall??&lt;/p&gt;
&lt;p&gt;The keyword we&apos;re looking for is called &lt;a href=&quot;https://grugq.github.io/docs/ul_exec.txt&quot;&gt;&quot;userland exec&quot;&lt;/a&gt;. It&apos;s a technique for executing a program without involving the kernel. The core idea is not too complicated: Linux programs use the ELF file format, which contains a description the exact memory layout a program expects when it runs. So we just parse the program as an ELF file, read the memory layout, then directly jump to the program&apos;s start address.&lt;/p&gt;
&lt;p&gt;&amp;lt;a href=&quot;https://fasterthanli.me/&quot; class=&quot;no-underline hover:underline&quot;&amp;gt;fasterthanlime&amp;lt;/a&amp;gt; has a blog post &lt;a href=&quot;https://fasterthanli.me/series/making-our-own-executable-packer/part-2&quot;&gt;describing exactly how to do that&lt;/a&gt; (part of a series of posts on building an executable packer), so be sure to give that a read if you want the fine details!&lt;/p&gt;
&lt;p&gt;But &lt;em&gt;we&apos;re&lt;/em&gt; gonna take the lazy path. and uhh... this is also not something you could do from a shell script[^userland-exec-shell-script]. So we&apos;re gonna handle all this &quot;userland exec&quot; stuff in Rust. That&apos;ll also let us &lt;s&gt;cheat&lt;/s&gt; leverage the breadth of Rust&apos;s package ecosystem by using the &lt;a href=&quot;https://crates.io/crates/userland-execve&quot;&gt;&lt;code&gt;userland-execve&lt;/code&gt;&lt;/a&gt; crate, which will handle the raw assembly and pointer manipulation for us. We&apos;re not gonna get our hands &lt;em&gt;too&lt;/em&gt; dirty today.&lt;/p&gt;
&lt;h3&gt;Rewriting it in Rust&lt;/h3&gt;
&lt;p&gt;Let&apos;s start first by porting our current shell script to Rust as-is. Let&apos;s set up a second crate next to our &lt;code&gt;lil-demo&lt;/code&gt; crate (so if you&apos;re in the &lt;code&gt;lil-demo&lt;/code&gt; directory still, run &lt;code&gt;cd ..&lt;/code&gt;). Run &lt;code&gt;cargo new run&lt;/code&gt; to create the crate, then put this in &lt;code&gt;run/src/main.rs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// run/src/main.rs
use std::os::unix::process::CommandExt as _;

fn main() {
    let current_exe = std::env::current_exe().unwrap();
    let portable_dir = current_exe.parent().unwrap();

    let ld_linux_so = portable_dir.join(&quot;ld-linux-x86-64.so.2&quot;);
    let lil_demo = portable_dir.join(&quot;lil-demo&quot;);

    let error = std::process::Command::new(ld_linux_so)
        .arg(lil_demo)
        .env(&quot;LD_LIBRARY_PATH&quot;, &amp;amp;portable_dir)
        .exec();
    panic!(&quot;failed to exec: {error}&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few notes on this version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It uses &lt;a href=&quot;https://doc.rust-lang.org/stable/std/env/fn.current_exe.html&quot;&gt;&lt;code&gt;std::env::current_exe()&lt;/code&gt;&lt;/a&gt; to find the &quot;portable dir&quot; path (equivalent to what we did in Bash)&lt;/li&gt;
&lt;li&gt;It builds a command to call &lt;code&gt;ld-linux.so&lt;/code&gt;, with the path to &lt;code&gt;lil-demo&lt;/code&gt; as an argument&lt;/li&gt;
&lt;li&gt;It sets &lt;code&gt;$LD_LIBRARY_PATH&lt;/code&gt; to the portable dir for the command&lt;/li&gt;
&lt;li&gt;It uses the (Unix-only) &lt;a href=&quot;https://doc.rust-lang.org/stable/std/process/struct.Command.html#method.exec&quot;&gt;&lt;code&gt;.exec()&lt;/code&gt;&lt;/a&gt; method, just like how we used &lt;code&gt;exec&lt;/code&gt; in Bash. It&apos;s a little unintuitive, but this method &lt;em&gt;should never return&lt;/em&gt; (it only returns if there was an error, which is why there&apos;s a &lt;code&gt;panic!()&lt;/code&gt; right after)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While in the &lt;code&gt;run&lt;/code&gt; directory, use these commands to build it and put it in our &lt;code&gt;lil-demo-portable&lt;/code&gt; directory (which is where &lt;code&gt;run&lt;/code&gt; expects to be):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cargo build
$ cp target/debug/run ../lil-demo/lil-demo-portable/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alright, now if we run our new &lt;code&gt;run&lt;/code&gt; program, we should see the same output as when we ran &lt;code&gt;run.sh&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ../lil-demo/lil-demo-portable/run
Hello from /your/path/to/lil-demo/lil-demo-portable/ld-linux-x86-64.so.2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Userland or bust&lt;/h3&gt;
&lt;p&gt;We&apos;re ready to swap over to &lt;a href=&quot;https://crates.io/crates/userland-execve&quot;&gt;&lt;code&gt;userland-execve&lt;/code&gt;&lt;/a&gt;. Add it to your dependencies by running &lt;code&gt;cargo add userland-execve&lt;/code&gt;, then update the code to use it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// run/src/main.rs
use std::ffi::CString;

fn main() {
    let current_exe = std::env::current_exe().unwrap();
    let portable_dir = current_exe.parent().unwrap();

    let ld_linux_so = portable_dir.join(&quot;ld-linux-x86-64.so.2&quot;);
    let lil_demo = portable_dir.join(&quot;lil-demo&quot;);

    let ld_linux_so_cstr = CString::new(ld_linux_so.to_str().unwrap()).unwrap();
    let lil_demo_cstr = CString::new(lil_demo.to_str().unwrap()).unwrap();
    let ld_library_path_env = CString::new(format!(
        &quot;LD_LIBRARY_PATH={}&quot;,
        portable_dir.to_str().unwrap()
    ))
    .unwrap();

    userland_execve::exec(
        &amp;amp;ld_linux_so,
        &amp;amp;[&amp;amp;ld_linux_so_cstr, &amp;amp;lil_demo_cstr],
        &amp;amp;[ld_library_path_env],
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So pretty similar structurally to the last one, except it uses &lt;code&gt;userland_execve::exec&lt;/code&gt; to run now-- the first argument is the file to execute, the second are the args[^userland-args], and the third are the env vars[^userland-env-vars]&lt;/p&gt;
&lt;p&gt;Rebuild the &lt;code&gt;run&lt;/code&gt; executable again, copy it over, and watch the magic unfold:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cargo build
$ cp target/debug/run ../lil-demo/lil-demo-portable/
$ ../lil-demo/lil-demo-portable/run
Hello from /your/path/to/lil-demo/lil-demo-portable/run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s now a &lt;em&gt;fully self-contained, portable Linux bundle&lt;/em&gt;! If you put this &lt;code&gt;lil-demo-portable&lt;/code&gt; directory on another Linux machine (of the same architecture), calling &lt;code&gt;run&lt;/code&gt; will run the same even if it doesn&apos;t have glibc or any other libraries installed globally, or even if the dynamic linker is missing&lt;/p&gt;
&lt;p&gt;Then, when &lt;code&gt;run&lt;/code&gt; gets called, it&apos;ll &lt;em&gt;actually&lt;/em&gt; run &lt;code&gt;lil-demo&lt;/code&gt;, which will &lt;em&gt;think&lt;/em&gt; it&apos;s own path is &lt;code&gt;run&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;wait but isn&apos;t this still wrong? don&apos;t we want it to think it&apos;s &lt;code&gt;lil-demo&lt;/code&gt;? not &lt;code&gt;run&lt;/code&gt;??&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ahh, well it&apos;s time to come clean...&lt;/p&gt;
&lt;h2&gt;Revealing the secret&lt;/h2&gt;
&lt;p&gt;Okay, here was the little curl example from a billion miles up the page[^billion-miles]:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./output/bin/curl --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There was a little sleight of hand earlier... &lt;code&gt;./output/bin/curl&lt;/code&gt; &lt;em&gt;is not actually curl at all&lt;/em&gt;. It&apos;s &lt;em&gt;actually&lt;/em&gt; a little substitute program, equivalent to the &lt;code&gt;run&lt;/code&gt; program from above! The &lt;em&gt;real&lt;/em&gt; curl is somewhere under &lt;code&gt;./output/brioche-resources.d&lt;/code&gt; with some unholy hash as part of its filename.&lt;/p&gt;
&lt;p&gt;The important thing is that, from an outside perspective, &lt;code&gt;./output/bin/curl&lt;/code&gt; quacks like curl, waddles like curl, and eats bread like curl.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But won&apos;t this still break for programs that care about &lt;code&gt;/proc/self/exe&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nope! Let&apos;s take Rust as an example. If you install Rust through Rustup, it&apos;ll create a directory structure like this somewhere under &lt;code&gt;~/.rustup&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bin/rustc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lib/librustc_driver.xxxxxx.so&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lib/libstd-xxxxxx.so&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rust uses &lt;code&gt;/proc/self/exe&lt;/code&gt; to find its current folder, then grabs libraries from &lt;code&gt;../lib&lt;/code&gt;. So if we replace &lt;code&gt;bin/rustc&lt;/code&gt; with a wrapper program like &lt;code&gt;run&lt;/code&gt;, Rust will read &lt;code&gt;/proc/self/exe&lt;/code&gt; and still think it&apos;s at the path &lt;code&gt;bin/rustc&lt;/code&gt;. So it&apos;ll resolve &lt;code&gt;../lib&lt;/code&gt; to the right directory-- no matter where the real Rust binary lives-- because it still &lt;em&gt;thinks&lt;/em&gt; it&apos;s at &lt;code&gt;bin/rustc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It also works for programs that execute themselves, since our little wrapper program runs exactly like the original program. The only thing that could break is if a program tries to read data from itself by opening its own path as a file, but that would obviously be very silly[^reading-executables]&lt;/p&gt;
&lt;h2&gt;Closing thoughts&lt;/h2&gt;
&lt;p&gt;So that&apos;s a peak behind the scenes for how &lt;a href=&quot;https://brioche.dev/docs/how-it-works/packed-executables/&quot;&gt;&quot;packed executables&quot;&lt;/a&gt; work in Brioche on Linux. Hopefully you&apos;ve walked away with the impression that there isn&apos;t &lt;em&gt;too much&lt;/em&gt; dark magic going on (or maybe you&apos;ve now seen horrors previously beyond your comprehension)&lt;/p&gt;
&lt;p&gt;I think this is just a really cool technique, and I&apos;d love to see it get adopted across other package managers or in other places where Linux executables get distributed! For Brioche, it means I can set up a fresh Brioche installation in a few seconds and start installing packages right away, without needing root permissions. It means that I can just run &lt;code&gt;brioche build -o output ...&lt;/code&gt; to get a bundle, then just &lt;code&gt;scp&lt;/code&gt; it to some remote Linux machine or send it to someone, even if Brioche isn&apos;t installed on the other side. It means the same bundle can be used both inside and outside a Docker container. It means I can just use glibc or whatever dynamically linked libraries I want, and not have to fiddle around with toolchains to make a fully-static build[^static-builds]&lt;/p&gt;
&lt;p&gt;You might also wonder: what does &lt;em&gt;making&lt;/em&gt; a nice, portable package look like if you use Brioche directly? Well, let&apos;s see what the config would look like to build a portable version of our &lt;code&gt;lil-demo&lt;/code&gt; project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// lil-demo/project.bri
import { cargoBuild } from &quot;rust&quot;;

export default function () {
  return cargoBuild({
    source: Brioche.glob(&quot;src&quot;, &quot;Cargo.*&quot;),
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...yep, that&apos;s it! No need to set up any wrappers explicitly, it&apos;s all handled automatically. All the build tools within Brioche are set up to add all these little wrapper binaries automatically out-of-the-box, so all your builds will work fully portably by default. Just like magic.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;[^the-container-up-my-sleeve-kinda]: Okay, technically, &lt;code&gt;brioche build -r curl&lt;/code&gt; should basically always be a cache hit, but if it isn&apos;t for some reason and it has to build from source, the build itself &lt;em&gt;would&lt;/em&gt; run in a container. The &lt;em&gt;output&lt;/em&gt; doesn&apos;t use any containers though&lt;/p&gt;
&lt;p&gt;[^small-container]: From commit &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/tree/97cfcce19268326d6c76458218b60c723c84225f&quot;&gt;&lt;code&gt;97cfcce&lt;/code&gt;&lt;/a&gt;, this example container came out to a size of 27 MB, which is pretty small (and glibc is 12 MB of that)! The official curl container image is still smaller at the time of writing (21 MB uncompressed) and that also includes both CA certificates and Busybox, but the big difference is that it uses musl instead of glibc. So getting a glibc-based curl container down to 27 MB is something I&apos;m still proud of overall! ...but in the real world, you&apos;d at least want to add CA certs to this image&lt;/p&gt;
&lt;p&gt;[^sandboxing-future]: There is build-time sandboxing, but once a package gets built, the result doesn&apos;t itself run in a sandbox. But, it&apos;d be possible to add a function in Brioche that &quot;sandbox-ifies&quot; another package, e.g. by using &lt;a href=&quot;https://github.com/containers/bubblewrap&quot;&gt;Bubblewrap&lt;/a&gt;. This would make sandboxing a composable piece, rather than being a core part of Brioche&apos;s design&lt;/p&gt;
&lt;p&gt;[^exec]: Running &lt;code&gt;exec ./some-program&lt;/code&gt; is almost the same as directly running &lt;code&gt;./some-program&lt;/code&gt;. The former &lt;em&gt;replaces&lt;/em&gt; the current process with the new program to execute by directly using the &lt;a href=&quot;https://man7.org/linux/man-pages/man2/execve.2.html&quot;&gt;&lt;code&gt;execve()&lt;/code&gt; syscall&lt;/a&gt;, where the latter runs it as a subprocess. If you haven&apos;t used &lt;code&gt;exec&lt;/code&gt; before, your homework assignment is to understand why it&apos;s the right tool for our &lt;code&gt;lil-demo&lt;/code&gt; wrapper&lt;/p&gt;
&lt;p&gt;[^proc-absolute-path]: Bonus points if you noticed that &lt;code&gt;/proc/self/exec&lt;/code&gt; is an absolute path, the exact thing we&apos;re trying to get rid of! Well, Linux is very Unix-y, meaning &quot;everything is a file&quot;, where &quot;everything&quot; includes several core APIs. These are implemented via special virtual filesystems, which get mounted at &lt;code&gt;/proc&lt;/code&gt;, &lt;code&gt;/sys&lt;/code&gt;, and &lt;code&gt;/dev&lt;/code&gt;. Because they&apos;re so critical, you really can&apos;t avoid them for some tasks... but that also means even extremely bare-bones environments have them mounted (e.g. Docker&apos;s &lt;code&gt;scratch&lt;/code&gt; container)&lt;/p&gt;
&lt;p&gt;[^userland-exec-shell-script]: Super bonus points to the first person to write a userland exec implementation in pure POSIX shell&lt;/p&gt;
&lt;p&gt;[^userland-args]: You may have noticed that we originally only passed one arg, but passed two when using userland exec. This is because the &lt;code&gt;userland-execve&lt;/code&gt; crate expects you to pass &lt;code&gt;argv0&lt;/code&gt; explicitly, whereas &lt;code&gt;std::process::Comamnd&lt;/code&gt; passes it implicitly by default.&lt;/p&gt;
&lt;p&gt;[^userland-env-vars]: Note that the example code will clear every env var except for &lt;code&gt;$LD_LIBRARY_PATH&lt;/code&gt;. If you want to inherit the rest of the env vars like &lt;code&gt;std::process::Command&lt;/code&gt; does, you&apos;ll need to manually iterate over &lt;a href=&quot;https://doc.rust-lang.org/stable/std/env/fn.vars_os.html&quot;&gt;&lt;code&gt;std::env::vars_os()&lt;/code&gt;&lt;/a&gt; and pass each one explicitly.&lt;/p&gt;
&lt;p&gt;[^billion-miles]: 1,609,344,000,000 km&lt;/p&gt;
&lt;p&gt;[^reading-executables]: Yep... horrifyingly, I have seen at least one package that directly reads an executable and looks for a specific byte pattern. I actually can&apos;t remember which package it was... but luckily it was only part of a test suite if I remember right&lt;/p&gt;
&lt;p&gt;[^static-builds]: Don&apos;t get me wrong, I love a good static build! It&apos;s just that setting up the build tooling and getting the right libraries for it can be a pain&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Brioche Project Update - August 2024</title><link>https://brioche.dev/blog/project-update-2024-08</link><guid isPermaLink="true">https://brioche.dev/blog/project-update-2024-08</guid><pubDate>Fri, 02 Aug 2024 03:50:42 GMT</pubDate><content:encoded>&lt;p&gt;So, it&apos;s been about two months since the &lt;a href=&quot;/blog/announcing-brioche&quot;&gt;initial public release of Brioche&lt;/a&gt;, so I thought it was about time to share what&apos;s been going on with the project! I quite like the newsletter-style updates that &lt;a href=&quot;https://this-week-in-rust.org/&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://dolphin-emu.org/blog/tags/progress%20report/&quot;&gt;Dolphin&lt;/a&gt; put out regularly, so I think I&apos;ll start doing something similar for Brioche (expect ~monthly updates)&lt;/p&gt;
&lt;h2&gt;Brioche releases&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/brioche-dev/brioche/blob/d09edd5102d243d04fe12cb79e2f832c42bd7584/CHANGELOG.md#v011---2024-06-09&quot;&gt;Brioche v0.1.1&lt;/a&gt; was released in early June, which helped smooth out some of the kinks from v0.1.0. The &lt;a href=&quot;https://github.com/brioche-dev/brioche/blob/d09edd5102d243d04fe12cb79e2f832c42bd7584/CHANGELOG.md#v011---2024-06-09&quot;&gt;changelog&lt;/a&gt; includes all the details, but to give a few highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Speed up registry syncing drastically and tweak registry timeouts&lt;/li&gt;
&lt;li&gt;Update the JS runtime to report the current version of Brioche. This will allow &lt;code&gt;std&lt;/code&gt; to detect the version before using a new recipe type (either returning an error or using a fallback implementation)&lt;/li&gt;
&lt;li&gt;Add a new &lt;code&gt;collect_references&lt;/code&gt; recipe type for use in the &lt;code&gt;std&lt;/code&gt; package&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I even included a subcommand to update Brioche itself, but uhhh... &lt;a href=&quot;https://github.com/brioche-dev/brioche/issues/95&quot;&gt;it&apos;s broken&lt;/a&gt;, so for now, you&apos;ll need to follow the &lt;a href=&quot;https://brioche.dev/docs/installation/&quot;&gt;installation instructions&lt;/a&gt; again to upgrade. Also unfortunately, I didn&apos;t catch this issue before v0.1.1 was released, so it&apos;s &lt;em&gt;still&lt;/em&gt; broken and the &lt;em&gt;next&lt;/em&gt; release will also require a manual upgrade... oops&lt;/p&gt;
&lt;h2&gt;Package updates&lt;/h2&gt;
&lt;p&gt;During the initial release, there were only 10 packages available: &lt;code&gt;ca_certificates&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt;, &lt;code&gt;miniserve&lt;/code&gt;, &lt;code&gt;nodejs&lt;/code&gt;, &lt;code&gt;rust&lt;/code&gt;, plus the &lt;code&gt;std&lt;/code&gt; package and a few miscellaneous ones (&lt;code&gt;hello_world&lt;/code&gt;, &lt;code&gt;typer&lt;/code&gt;, &lt;code&gt;smol_toml&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Now, there are 38, almost 4x as many as during the original launch! Here&apos;s what&apos;s available now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alsa_lib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;broot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;carapace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dust&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eza&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gitui&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;go&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;joshuto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jujutsu&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jwt_cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k9s&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lurk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oha&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oniguruma&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openssl&lt;/code&gt; (split out from &lt;code&gt;std&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opentofu&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pcre2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ripgrep&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ruff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tcsh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tokei&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xplr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xsv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zoxide&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Massive kudos for these packages go to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt;, who opened 31 and 7 Pull Requests, respectively!&lt;/p&gt;
&lt;p&gt;There were also several breaking changes made to Rust, NodeJS, and Go, to make building packages more consistent. See the PRs &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/65&quot;&gt;brioche-packages#65&lt;/a&gt; and &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/67&quot;&gt;brioche-packages#67&lt;/a&gt; for an overview of the changes.&lt;/p&gt;
&lt;h2&gt;std updates&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;std&lt;/code&gt; package has also seen quite a few changes. Note that it&apos;s still pretty volatile, so keep an eye on the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/0bb7a9871953eac009744407e76e956daf8a5c92/packages/std/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt; to see how it evolves.&lt;/p&gt;
&lt;p&gt;Since the initial release, there have been quite a few changes! Here&apos;s the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/0bb7a9871953eac009744407e76e956daf8a5c92/packages/std/CHANGELOG.md#2024-07-12-breaking&quot;&gt;full list of changes since the initial release&lt;/a&gt;, but here are the highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove Python and OpenSSL from &lt;code&gt;std.toolchain()&lt;/code&gt;. OpenSSL was added as its own package (&lt;code&gt;openssl&lt;/code&gt;), and Python will join it soon!&lt;/li&gt;
&lt;li&gt;Overhaul recipe casting. See &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/25&quot;&gt;brioche-packages#25&lt;/a&gt; for more context&lt;/li&gt;
&lt;li&gt;Replace the &lt;code&gt;std.auotwrap()&lt;/code&gt; function with &lt;code&gt;std.autopack()&lt;/code&gt;. Migrating to the new function should be fairly straightforward, and the new function provides a lot more options&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;std.BRIOCHE_VERSION&lt;/code&gt; to check which version of Brioche is being used. This will mainly be used by &lt;code&gt;std&lt;/code&gt; itself for feature detection&lt;/li&gt;
&lt;li&gt;Optimize container sizes made with &lt;code&gt;std.ociContainerImage()&lt;/code&gt;. When using Brioche &amp;gt;=0.1.1, container images can now be much smaller!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Brioche core updates&lt;/h2&gt;
&lt;p&gt;I was hoping to have a v0.1.2 release ready to go before publishing the first project update, but alas, it&apos;s not ready to go quite yet...&lt;/p&gt;
&lt;p&gt;...but that also means there are a few goodies in the &lt;code&gt;main&lt;/code&gt; branch that you can look forward to for the next release!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Updates to several subcommands (&lt;code&gt;fmt&lt;/code&gt;, &lt;code&gt;check&lt;/code&gt;, &lt;code&gt;publish&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;) so they can take more than one package at a time.&lt;/strong&gt; When working with multiple Brioche projects (say, if you&apos;re &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages?tab=readme-ov-file#contributing-new-packages&quot;&gt;contributing a new package&lt;/a&gt;), you can now save time by passing the &lt;code&gt;-p&lt;/code&gt; or &lt;code&gt;-r&lt;/code&gt; flag more than once! Once again, huge thanks to &lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; for contributing these changes!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Add support for &quot;locked downloads&quot; with &lt;code&gt;Brioche.download&lt;/code&gt; expressions.&lt;/strong&gt; Normally when downloading something with Brioche, you need to provide the download hash explicitly in code. This has long led to an awkward dance where you need to get the URL, download it yourself first, get the hash, then paste it in the code. Well, as long as the URL is static in your source code, you&apos;ll no longer need to do this! Just change from this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Old way, need to specify the hash manually
const source = std
  .download({
    url: &quot;https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-1.7.1.tar.gz&quot;,
    hash: std.sha256Hash(
      &quot;478c9ca129fd2e3443fe27314b455e211e0d8c60bc8ff7df703873deeee580c2&quot;,
    ),
  })
  .unarchive(&quot;tar&quot;, &quot;gzip&quot;)
  .peel();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// New way, hash gets saved to the lockfile
const source = Brioche.download(
  &quot;https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-1.7.1.tar.gz&quot;,
)
  .unarchive(&quot;tar&quot;, &quot;gzip&quot;)
  .peel();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and the URL will automatically be downloaded and recorded in the lockfile! Note that this will require an update to the &lt;code&gt;std&lt;/code&gt; package too, which is &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/pull/75&quot;&gt;still in draft&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Registry updates&lt;/h2&gt;
&lt;p&gt;Right after release, &lt;a href=&quot;https://github.com/matklad&quot;&gt;&lt;strong&gt;@matklad&lt;/strong&gt;&lt;/a&gt; opened a &lt;a href=&quot;https://brioche.zulipchat.com/#narrow/stream/440653-general/topic/Why.20so.20slow.3F/near/442736995&quot;&gt;Zulip discussion&lt;/a&gt; to ask why installing &lt;code&gt;hello_world&lt;/code&gt; took so long (and then also contributed &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/54&quot;&gt;brioche#54&lt;/a&gt; to help stop the bleeding).&lt;/p&gt;
&lt;p&gt;After a lot of back-and-forth with testing, I got some general fixes in place that went out with Brioche v0.1.1, but it still wasn&apos;t a great experience. After a lot of investigation, &lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt; and I ended up doing a major change to &lt;a href=&quot;https://github.com/brioche-dev/brioche-registry&quot;&gt;the registry&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To cut a long story short, the registry runs on ephemeral &lt;a href=&quot;https://fly.io/&quot;&gt;Fly.io&lt;/a&gt; machines, and I originally used &lt;a href=&quot;https://fly.io/docs/litefs/&quot;&gt;LiteFS&lt;/a&gt; for the database (basically, SQLite with replication). LiteFS ended up causing a lot of latency and reliability issues, so we ended up migrating to a Postgres database hosted by &lt;a href=&quot;https://neon.tech/&quot;&gt;Neon&lt;/a&gt; (which, so far, has been an &lt;em&gt;amazing&lt;/em&gt; database host!)&lt;/p&gt;
&lt;p&gt;Now, the registry should respond much faster, even when a Fly.io machine has to do a cold start!&lt;/p&gt;
&lt;h2&gt;Coming soon&lt;/h2&gt;
&lt;p&gt;To close this out, I wanted to share a shortlist of things currently in progress and things I&apos;d like to make progress on in the near future! But... consider this more of a &quot;wishlist&quot; than a &quot;roadmap&quot;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jaudiger&quot;&gt;&lt;strong&gt;@jaudiger&lt;/strong&gt;&lt;/a&gt; opened &lt;a href=&quot;https://github.com/brioche-dev/brioche/pull/105&quot;&gt;brioche#105&lt;/a&gt; to upgrade Deno Core to the latest version. There&apos;s still quite a bit of work left to get this working and mergeable, but I&apos;m hoping this will make it in soon!&lt;/li&gt;
&lt;li&gt;Add a new &lt;code&gt;std.glob()&lt;/code&gt; function, which will take a recipe and keep only the files matching a glob pattern&lt;/li&gt;
&lt;li&gt;More cleanup to &lt;code&gt;std.toolchain()&lt;/code&gt;, especially around autotools (you need to do &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/blob/0bb7a9871953eac009744407e76e956daf8a5c92/packages/jq/project.bri#L33-L34&quot;&gt;some hacky stuff&lt;/a&gt; to use autotools currently)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/asheliahut&quot;&gt;&lt;strong&gt;@asheliahut&lt;/strong&gt;&lt;/a&gt; made some progress on &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/tree/add-cmake&quot;&gt;CMake&lt;/a&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/commit/598d90cbfad77d56e5e32f1d0c86f05c496b0302&quot;&gt;permalink&lt;/a&gt;) and &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/tree/python-build-temp&quot;&gt;Python&lt;/a&gt; (&lt;a href=&quot;https://github.com/brioche-dev/brioche-packages/commit/0502ab44e451b93c357b263b3aa625143b3af999&quot;&gt;permalink&lt;/a&gt;). Both open up lots of new packages that can be added!&lt;/li&gt;
&lt;li&gt;Cross-platform support and cross-compilation are going to be fairly massive tasks, but I&apos;d like to start making some progress towards these. ARM64 Linux will probably be the second supported target, and macOS will be further down the line.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Kyle Lacy</author></item><item><title>Announcing Brioche!</title><link>https://brioche.dev/blog/announcing-brioche</link><guid isPermaLink="true">https://brioche.dev/blog/announcing-brioche</guid><pubDate>Mon, 03 Jun 2024 00:54:32 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;m super excited to announce the first public release of Brioche! Brioche is a brand new package manager and build tool that builds on top of the best ideas of other package managers, like Nix, Homebrew, and Cargo. It&apos;s designed to be flexible and easy to use, and it leverages TypeScript for fancy typechecking and autocompletions in your build scripts.&lt;/p&gt;
&lt;p&gt;I&apos;d consider this release a &lt;strong&gt;Technical Preview&lt;/strong&gt;. Currently, it&apos;s limited to x86-64 Linux only, there&apos;s only a small number of packages, and there are still some outstanding issues, including pretty bad performance issues and bugs in the Language Server Protocol implementation. Brioche isn&apos;t really at the point I&apos;d recommend folks use it for Serious Business™ yet... but, everything is &lt;em&gt;working&lt;/em&gt;, and I&apos;m finally at the point where I&apos;m ready to get some more eyes on the project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;ve heard of &lt;a href=&quot;https://www.tangram.dev/&quot;&gt;Tangram&lt;/a&gt; before, Brioche might looks pretty familiar because Brioche heavily borrows ideas from it too. There&apos;s a bit of a history there, which I &lt;a href=&quot;#on-tangram&quot;&gt;touch on below&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;...Anyway, without further ado, here&apos;s a fairly simple Brioche project file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// project.bri

// Import dependencies
import * as std from &quot;std&quot;;
import { cargoBuild } from &quot;rust&quot;;

// This will get built by default
export default function app() {
  // Build a Rust project with Cargo
  return cargoBuild({
    // Import Cargo files to build
    crate: Brioche.glob(&quot;src&quot;, &quot;Cargo.*&quot;),

    // Define the path of the default binary to run
    runnable: &quot;bin/hello&quot;,
  });
}

// Define an extra export that builds a container
export function container() {
  // Wrap the Rust build into an OCI container image
  return std.ociContainerImage({
    recipe: app(),
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Brioche.glob&lt;/code&gt; line imports files from disk next to the &lt;code&gt;project.bri&lt;/code&gt; file, so this particular script is meant to live alongside an existing Rust project. Besides that, hopefully it&apos;s pretty self-explanatory what&apos;s going on. A few things you can do with this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can run &lt;code&gt;brioche run&lt;/code&gt;, which will call the default export function. This returns a &lt;a href=&quot;/docs/core-concepts/recipes&quot;&gt;&lt;strong&gt;recipe&lt;/strong&gt;&lt;/a&gt; that will use the Rust compiler to build the project. Then, Brioche will call the &lt;code&gt;bin/hello&lt;/code&gt; binary&lt;/li&gt;
&lt;li&gt;You can run &lt;code&gt;brioche build -e container -o container.tar&lt;/code&gt; to call the &lt;code&gt;container&lt;/code&gt; function. This will build an OCI container image, ready to be imported into either Docker or Podman&lt;/li&gt;
&lt;li&gt;You can run &lt;code&gt;brioche build -o output/&lt;/code&gt; to save a directory containing &lt;code&gt;bin/hello&lt;/code&gt;. Not just that: this directory will contain all of the runtime dependencies for the project (including glibc)! That means you can send it to another computer, and it&apos;ll run using the exact same dependencies you just ran it with&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to check out some more examples or if you want to give Brioche a spin yourself, take a look at the &lt;a href=&quot;/docs&quot;&gt;documentation&lt;/a&gt;. If you want to see the currently available packages (or just want to explore some real-world Brioche code), check out the &lt;a href=&quot;https://github.com/brioche-dev/brioche-packages&quot;&gt;brioche-packages repo&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Why write another package manager?&lt;/h2&gt;
&lt;p&gt;There are &lt;em&gt;lots&lt;/em&gt; of tools that cover some or all of the use-cases I had in mind for Brioche: Nix, Bazel, Earthly, Homebrew, asdf, direnv, devenv, tea, and too many more to list. So why spend the time building something new?&lt;/p&gt;
&lt;p&gt;Well, first off, it&apos;s fun! Brioche has been one of my favorite projects to work on. Rust and TypeScript are my two favorite languages to write, and I love the fairly low-level nature of working with compiler toolchains (even if dealing with autotools is endlessly frustrating...)&lt;/p&gt;
&lt;p&gt;Second, Nix. A long long time ago (circa 2016), I daily drove NixOS and even briefly maintained a package in the Nixpkgs repo. I was really sold on Nix&apos;s ideas, but I eventually abandoned it because I ended up feeling pretty frustrated when using it. I learned Nix-the-language pretty in-depth, but it never really felt intuitive to me. Derivations always felt weirdly rigid. I didn&apos;t like that the Nixpkgs repo as a whole is versioned as one unit instead of individual packages. I didn&apos;t like how much work I had to put in to get stuff that just works out-of-the-box everywhere else to work on NixOS: I felt like my tools work working &lt;em&gt;against&lt;/em&gt; me instead of &lt;em&gt;for&lt;/em&gt; me.&lt;/p&gt;
&lt;p&gt;2016 was 8 years ago now, and I know the Nix ecosystem has evolved a lot since then. I know Flakes are supposed to be a game changer, there are lots more packages and resources for using Nix, and the core tooling has certainly been improved a lot since then. But it was this experience that planted the idea for Brioche in my head, and I couldn&apos;t shake the feeling that, starting from scratch, I could design something less quirky than Nix while keeping its best features.&lt;/p&gt;
&lt;h2&gt;What&apos;s in store for Brioche&lt;/h2&gt;
&lt;p&gt;In the short term, there&apos;s lots of things I want to get done: improve performance (I have a lot of ideas here), add more packages, make it easier to do more exotic builds, get Brioche working on more platforms, etc.&lt;/p&gt;
&lt;p&gt;In the long term, I want Brioche to be the best way to manage your software projects. I end up finding myself mixing and matching lots of tools in weird ways: I&apos;ve had projects that mix Rust and TypeScript, Rust and ffmpeg, Rust and Swift, Rust and the Windows API, Rust and Godot, Rust and SDL2, etc. (did I mention I like Rust?)&lt;/p&gt;
&lt;p&gt;My dream is that I could use Brioche for all of these projects. I want to make a project and have all of its external dependencies tracked in a lockfile. I want to run one command that takes care of building, seeding my test databases, checking formatting, then starting a server in watch mode with my database running alongside. I want to use the same build configuration locally, for a container image, and for CI builds. And I want it to work without virtualization whether I&apos;m using Windows on my desktop, macOS on my laptop, or Linux on the server (and Linux on the desktop when I can finally run all the games I want through Proton)&lt;/p&gt;
&lt;h2&gt;On the Nix community&lt;/h2&gt;
&lt;p&gt;The Nix community has recently &lt;a href=&quot;https://lwn.net/Articles/970824/&quot;&gt;been going through Something&lt;/a&gt;. My decision to build Brioche was in no way a reaction to the recent fallout around Nix. I still have a ton of respect for Nix as a community, and I&apos;m genuinely rooting for them to establish a solid governance model that puts the community first so Nix-the-project can thrive.&lt;/p&gt;
&lt;h2&gt;On Tangram&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.tangram.dev/&quot;&gt;Tangram&lt;/a&gt; is another package manager that has a lot of overlap with Brioche: it&apos;s heavily Nix-inspired, it uses TypeScript for build scripts, it&apos;s written in Rust, and generally Brioche build scripts look pretty similar to Tangram build scripts. At the time of writing, Tangram hasn&apos;t yet been released, but it&apos;s due to release very soon.&lt;/p&gt;
&lt;p&gt;The similarities between Tangram and Brioche aren&apos;t a coincidence: I worked for Tangram, Inc. starting in October 2022 to April 2023, when I was fired (I felt this was an unfair decision, but I&apos;m not here to tell that story). I had been working on Brioche before my time there, and I decided to resume it some time after I was no longer employed by Tangram.&lt;/p&gt;
&lt;p&gt;On reflection, I felt there were some parts of Tangram&apos;s design that would work well for the goals I had for Brioche, and some that didn&apos;t align with my goals[^1], so I simply incorporated what I learned at Tangram into the current iteration of Brioche. I think it&apos;s fair to say that Brioche is, ethically, a fork of Tangram, even though haven&apos;t used any code from Tangram directly (although I am still using some prebuilt static Busybox/Dash/env binaries that Tangram built/published). This is also why the &lt;a href=&quot;https://github.com/brioche-dev/brioche/blob/2dd8b881b68adb090c5115e245c3dbc1ee605e6c/LICENSE.md&quot;&gt;Brioche license&lt;/a&gt; includes a copyright notice from Tangram. Brioche was work-in-progress well before my time at Tangram, Inc. but I wanted to acknowledge that Tangram was the source for several design decisions I made in Brioche.&lt;/p&gt;
&lt;p&gt;[^1]: In an earlier version of this post, I felt I worded my feelings about Tangram&apos;s design decisions poorly. I had said that I thought there were elements of Tangram&apos;s design that didn&apos;t work as well, but I should&apos;ve clarified that I meant &lt;em&gt;in the context of my goals for Brioche&lt;/em&gt; specifically. I&apos;ve tweaked some sections where I talked about Tangram, and my apologies for anyone that walked away with a different impression on Tangram after reading the first version of this article.&lt;/p&gt;
</content:encoded><author>Kyle Lacy</author></item></channel></rss>