10 interesting stories served every morning and every evening.

LLMs are eroding my software engineering career and I don't know what to do

human-in-the-loop.bearblog.dev

06 Jun, 2026

I’m a soft­ware en­gi­neer, com­plet­ing 10 years of pro­fes­sional ex­pe­ri­ence this year. I started my ca­reer as a web fron­tend en­gi­neer (it was eas­ier for me to de­bug fron­tend code back then, so I chose that path), but shortly tran­si­tioned to (web) back­end and never looked back.

Through a se­ries of co­in­ci­dences, once I stepped into back­end de­vel­op­ment, I ended up work­ing in soft­ware de­vel­op­ment roles in the do­mains of fi­nance, book­keep­ing and pay­ment pro­cess­ing, where I had great au­ton­omy and a close and can­did re­la­tion­ship with Product Managers and stake­hold­ers.

I learnt a lot about the do­main and how to ef­fec­tively write pro­grams for it: PCI com­pli­ance, dou­ble-en­try ledgers, es­crows, rec­on­cil­i­a­tion, pay­ment life­cy­cles, bank trans­fer idem­po­tency, etc.

It was, then, ob­vi­ous that I should fo­cus my ca­reer on be­com­ing an ex­pert on that do­main to stand out as a pro­fes­sional and dif­fer­en­ti­ate my­self in a field that showed signs of an in­creas­ing need for do­main spe­cial­ists.

The first pil­lar to erode: do­main-spe­cific knowl­edge

Last year, I got hired by a com­pany in the fi­nance work­space. So far, I had worked on com­pa­nies that do have a strong pay­ment and fi­nance com­po­nent to their op­er­a­tions/​of­fer­ings, but that were not solely fi­nance-fo­cused com­pa­nies.

That com­pany also em­braced AI whole­heart­edly, so I got ChatGPT and Claude Enterprise ac­counts from day one and was en­cour­aged to use them for my re­search, ex­plo­ration, and even cod­ing, al­beit with a warn­ing that I should still re­view and own every sin­gle line that made it into pro­duc­tion.

One of my first pro­jects in­volved re­work­ing the legacy on­line pay­ment sys­tem, which was a mess. They hired me for (among other things) my pre­vi­ous ex­pe­ri­ence in build­ing that and trusted me with the task.

Different from the other com­pa­nies I had worked for so far, they wanted the Design Docs” I write be­fore cod­ing to be read­able by both en­gi­neers and prod­uct man­agers - so they should­n’t be a tech­ni­cal deep dive and more of an ar­chi­tec­tural view. I wrote my first one with min­i­mal AI as­sis­tance - I even called LLMs stochastic par­rots” at the time, a view I no longer hold - and de­liv­ered it.

I val­ued my knowl­edge and thought no LLMs could re­place it.

Then my man­ager reached out to me: even though you’re de­liv­er­ing code at a good pace, you’re tak­ing too long to de­liver those Design Docs. Are you us­ing AI? You should use more AI.

No way this will work”, I thought in my head, but agreed. The mod­els at that time were not as good as the ones we have now, but they did pro­vide a good speed-up on my writ­ing and even the de­ci­sion-mak­ing.

And then I started re­al­iz­ing: all the knowl­edge I have ac­cu­mu­lated over the years: the trade-offs be­tween im­ple­men­ta­tions, how ac­quir­ing works, how to struc­ture idem­po­tency to pre­vent dou­ble-charges, every­thing, was be­com­ing use­less. Even though the mod­els still needed some steer­ing, they could con­nect the dots on how to struc­ture such sys­tems, which was the hard­est part that only de­vel­ops in your brain af­ter years of hands-on ex­pe­ri­ence. That was my first shock.

But sure, I thought, they can do that be­cause there’s plenty of ar­ti­cles on the web on how that shit works along with all the tech­ni­cal doc­u­men­ta­tion, and we have blog posts ex­plain­ing how to ap­ply the tech­ni­cal tools to the do­main. For hu­mans, it may take a long time to learn all that, but that’s train­ing data so the mod­els can pick it up.

What the mod­els will never be good at, and that’s where hu­mans will shine, is de­bug­ging! I had ac­cu­mu­lated a good ex­pe­ri­ence de­bug­ging race con­di­tions and dis­trib­uted sys­tems in pro­duc­tion. That was my ticket to long-term em­ploy­a­bil­ity.

The sec­ond pil­lar to erode: de­bug­ging and dis­trib­uted sys­tems

So, af­ter LLMs started get­ting good at writ­ing docs and help­ing plan the ac­tual im­ple­men­ta­tions, they be­came good at cod­ing. It started in the sec­ond half of 2025 with the Claude Code hype, then Codex came and so on. Although I was us­ing LLMs for writ­ing unit tests every day be­fore that, I was­n’t trust­ing them to write the full im­ple­men­ta­tion yet.

The nat­ural next step was to in­tro­duce more AI into writ­ing code. And hon­estly, I liked it. I like ship­ping things to pro­duc­tion and see­ing users happy as much as I like cod­ing, so I was trad­ing one thing that I like for an­other one that I also like, it was fair.

LLMs were be­com­ing good at cod­ing, but it still could­n’t de­bug the mess left be­hind (by then or by the hu­mans), so I still had a role that was big­ger than steer­ing the ro­bot - a ticket to em­ploy­a­bil­ity.

Everything seemed fine.

Then came the MCPs, the agen­tic work­flows and Claude 4.5 and the sky started to fall.

Claude 4.5, to be hon­est, was­n’t that good. It solved like 60% of the bugs given a stack trace and some con­text (a Sentry link with Sentry MCP en­abled was all it took in most cases). Sometimes it gave a so­lu­tion that sounded plau­si­ble but was to­tally wrong.

This time, how­ever, I stopped doubt­ing the ma­chines. I saw bugs that in the past would eas­ily take 1 day of full-time de­bug­ging be­ing one-shot­ted by Claude Code. Of course, not all of them yet, but the pat­tern was clear.

Then came 4.6, 4.7, GPT 5.5, Opus 4.8 and the DataDog MCP… Now I have CLIs that one-shots bugs across dis­trib­uted sys­tems for me. Bugs that I could­n’t solve in the past. Bugs that would take 2 days of full-time de­bug­ging. Bugs across dis­trib­uted sys­tems that lack dis­trib­uted ob­serv­abil­ity. 90% of the bugs are one-shot­ted now, in­clud­ing bizarre race con­di­tions, un­ex­pected cor­ner-cases, third-party in­te­gra­tion is­sues, un­doc­u­mented API edge cases, every­thing. I hardly have to in­ter­vene.

Of course, I’m still em­ploy­able be­cause some­one has to re­view the code and steer the ro­bot. But I’m just an­other off-the-shelf en­gi­neer now. I have no do­main ex­per­tise that an­other Sr. en­gi­neer steer­ing an LLM can­not match. All my fi­nance and pay­ment do­main ex­per­tise, all the de­bug­ging in­tu­ition and dis­trib­uted sys­tem knowl­edge earned through hours of sweat and tears, is now prompt­able.

We were taught that gen­er­al­ists and spe­cial­ists will al­ways have their roles. But now the mar­ket is shap­ing every­one into be­com­ing a gen­er­al­ist. That’s not a bad thing per se, un­til you look un­der the eco­nom­ics of sup­ply and de­mand: if every­one is a gen­er­al­ist, the price of a gen­er­al­ist falls if there’s no de­mand to match. And we all know the de­mand is dry­ing up.

The third pil­lar, the one that has­n’t eroded yet: code qual­ity and ar­chi­tec­ture

I still have one pil­lar stand­ing, though: code qual­ity and soft­ware ar­chi­tec­ture - what’s now be­ing re­duced to be­ing called taste” 1.

Along the course of my ca­reer, I al­ways liked to refac­tor, al­ways prized good code, and ne­go­ti­ated time in the sprint for it. DDD, Hexagonal, Clean Architecture, you know all the buzz­words. I like this topic, I like to dis­cuss the trade-offs and dif­fer­ent ideas on how to shape code­bases. I re­ally like it.

This is the last pil­lar stand­ing. Except that no­body cares any­more.

Agents do a re­ally bad job at keep­ing code­bases or­ga­nized. If you don’t steer them, they’ll hit a cir­cu­lar de­pen­dency is­sue sooner than you think. Will du­pli­cate code. Add un­nec­es­sary com­ments. Mix up pure func­tions and side-ef­fects. Disregard the prin­ci­ples of SOLID.

That should keep hu­mans em­ployed, ex­cept that this skill is now be­ing re­duced to the word taste”. But it’s not just a re­nam­ing, the in­dus­try is mov­ing to a world where code or­ga­ni­za­tion is less im­por­tant.

Sure, hu­mans should steer the agent to pre­vent spaghetti code­bases with cir­cu­lar de­pen­dency graphs. We don’t want F-rated code­bases that are im­pos­si­ble to touch with­out break­ing some­thing. But a C or D? It’s now fine. Nobody needs A or B-grade code­bases any­more be­cause they’re be­ing made for LLMs, not for hu­mans to read.

I don’t want to ar­gue if this is in­her­ently good or bad. If the source code is now writ­ten for ma­chines to read and not hu­mans, it may be ac­tu­ally ok to tar­get them.

But that’s an­other pil­lar of my ex­per­tise that’s erod­ing. A good chunk of the knowl­edge I ac­cu­mu­lated on that topic is not that valu­able any­more. All the time I spent on it - read­ing books, do­ing real-world ex­er­cises, dis­cussing with other en­gi­neers, writ­ing ADRs - is be­com­ing use­less.

What now?

I’m still em­ployed and I see my­self em­ployed (at least in that com­pany) for a fore­see­able fu­ture. But I don’t know what to think about the long-term.

I spent 10 years (even more when you ac­count for non-pro­fes­sion ex­pe­ri­ence) get­ting good at things that are be­com­ing less and less valu­able. My last pil­lar of ex­per­tise is now re­duced to a taste” and will prob­a­bly won’t last long.

And I know that’s not just me. About 8 months ago there was a lay­off at my cur­rent com­pany (not re­lated to AI, ac­cord­ing to them). Some bril­liant ex-cowork­ers were laid off and are still look­ing for jobs. Most of them suf­fer from the same prob­lem I out­lined here: their do­main ex­per­tise is not enough to stand out any­more.

The com­pany is now hir­ing again for a few roles and do­main fa­mil­iar­ity is not a strong dif­fer­en­tia­tor any­more. We used to list Software Engineer - Area”. Now it’s just Software Engineer” and the team as­sign­ment comes af­ter the of­fer is ac­cepted.

Of course, this is good for bril­liant en­gi­neers that never had the chance to get deep into the do­main and now have bet­ter chances at get­ting a job, but it’s also sad to think that other bril­liant en­gi­neers that spent their lives col­lect­ing do­main knowl­edge are now com­pet­ing on the same lane.

The only way out for keep­ing my em­ploy­a­bil­ity in the long-term now seems to be shift­ing my do­main ex­per­tise to some­thing LLMs will not get good at so eas­ily. But what’s left?

I thought about go­ing back to col­lege, learn­ing Math, Statistics, ad­vanced Machine Learning and ap­ply­ing for re­search role at a fron­tier lab. Except that there are no fron­tier labs in my coun­try, the few ones that ex­ist are flood­ing with ap­pli­ca­tions and I have fam­ily mat­ters that makes mov­ing to an­other coun­try dif­fi­cult. By the time I can af­ford to make that jump, RSI may have made re­searchers ob­so­lete.

Maybe I should con­sider trans­form­ing my wood­work­ing hobby into a pro­fes­sion…

Update (Jun 7): this post went vi­ral. I wrote an­other post re­ply­ing to some com­ments from so­cial me­dia and ex­pand­ing some of my ar­gu­ments. You can read it here.

See this, this and this for ref­er­ence. Don’t take this as an en­dorse­ment of the con­tent in­side any of these posts.↩

See this, this and this for ref­er­ence. Don’t take this as an en­dorse­ment of the con­tent in­side any of these posts.↩

#ai

#llm

#software en­gi­neer­ing

[FEATURE] Official Claude Desktop build for Linux (Ubuntu LTS / Debian)

github.com

Preflight Checklist

I have searched ex­ist­ing re­quests and this fea­ture has­n’t been re­quested yet

This is a sin­gle fea­ture re­quest (not mul­ti­ple fea­tures)

Problem Statement

Preflight note. The clos­est open is­sue is #40347. Related: #47316 (closed), #38276 (closed as out of scope for this repo), #36011 (stale). I am fil­ing this as a con­sol­i­da­tion and ex­ten­sion of #40347 with cor­rected tech­ni­cal fram­ing (Claude Code plu­gin de­vel­op­ment against Desktop ex­ten­sions), named pri­mary sourc­ing for the Cowork Linux-VM ar­chi­tec­ture, and cur­rent mar­ket data. Happy to merge into #40347 if main­tain­ers pre­fer; please route rather than close if a dif­fer­ent venue is cor­rect.

On scope: this is­sue con­cerns Claude Code in two con­crete ways. (1) Claude Code plu­g­ins are de­vel­oped and tested against Claude Desktop ex­ten­sions, which has no Linux build, so plu­gin work cur­rently re­quires switch­ing OS. (2) Cowork in­vokes the Claude Code bi­nary in­side a Linux VM on ma­cOS, so the Linux ex­e­cu­tion path al­ready ex­ists in­side the Claude Code prod­uct and is the prac­ti­cal thing miss­ing as a pub­lished tar­get.

What this is­sue is ask­ing for A pub­lic Anthropic po­si­tion on Linux desk­top sup­port, and ide­ally a first-party build. A rea­soned not on the cur­rent roadmap, and here is why” would re­solve most of what this is­sue is about. There is, to my knowl­edge, no pub­lic state­ment on Linux desk­top sup­port; the ab­sence is it­self part of the prob­lem.

Current state

Anthropic dis­trib­utes Claude Desktop for ma­cOS and Windows only. The of­fi­cial down­load page states Not avail­able for Linux”. Claude Code (the CLI) runs na­tively on Linux but is a ter­mi­nal tool, not a sub­sti­tute for the desk­top GUI. Desktop ex­ten­sions (the sur­face Claude Code plu­g­ins are tested against), com­puter use, desk­top dic­ta­tion and Cowork are avail­able only in Claude Desktop. Linux users there­fore have no of­fi­cially sup­ported graph­i­cal path to these ca­pa­bil­i­ties, and in par­tic­u­lar no way to de­velop and test Claude Code plu­g­ins as desk­top ex­ten­sions with­out switch­ing to ma­cOS or Windows.

Why this is struc­turally hard to jus­tify Anthropic al­ready builds, signs and dis­trib­utes Linux soft­ware. Per code.claude.com/​docs/​en/​setup, Claude Code ships signed apt, dnf and apk repos­i­to­ries and per-ar­chi­tec­ture bi­na­ries (linux-x64, linux-ar­m64, musl vari­ants). The pipeline ex­ists.

The Cowork agent al­ready de­pends on Linux in­side the prod­uct. Independent re­verse-en­gi­neer­ing by Simon Willison on launch day (12/01/2026), cor­rob­o­rated by Pluto Security and pvieito (“Inside Claude Cowork”), found that on ma­cOS Cowork boots a cus­tom Ubuntu 22.04 VM via Apple’s Virtualization Framework (VZVirtualMachine) and runs the Claude Code bi­nary in­side it un­der bub­blewrap and sec­comp. Anthropic’s own doc­u­men­ta­tion con­firms the hy­per­vi­sor split: Apple Virtualization.framework on ma­cOS, Hyper-V on Windows. The com­mu­nity pro­ject johnz­fitch/​claude-cowork-linux demon­strates the same Cowork mode run­ning na­tively on Linux x86_64 by stub­bing the ma­cOS na­tive mod­ules and skip­ping the VM en­tirely. The Linux ca­pa­bil­ity al­ready ex­ists in­side the prod­uct; what’s miss­ing is a pub­lished Linux tar­get.

Why it mat­ters that it is miss­ing Claude Desktop han­dles OAuth to­kens, API keys, and ex­ten­sion con­fig­u­ra­tions. It is a cre­den­tial-han­dling ap­pli­ca­tion run­ning on de­vel­oper work­sta­tions.

Linux users cur­rently ob­tain it via third-party repack­ages of the Windows Electron build. The lead­ing pro­ject, aad­drick/​claude-desk­top-de­bian (roughly 4.5k stars), is gen­uinely high qual­ity: signed apt and dnf repos­i­to­ries, .deb/.rpm/AppImage/AUR/Nix builds, CI-tested, a –doctor di­ag­nos­tic, and up­stream track­ing within days (latest re­lease 05/06/2026, track­ing Claude Desktop 1.11187.1). It is also, by de­f­i­n­i­tion, not ven­dor-signed and not ven­dor-au­dited. A non-triv­ial num­ber of Claude users en­trust their cre­den­tials and lo­cal filesys­tem ac­cess to a third-party repack­age be­cause Anthropic ships noth­ing of­fi­cial. The struc­tural risk is not about the cur­rent main­tain­ers; it is the prece­dent on a plat­form Anthropic’s own agent run­time de­pends on.

Linux is not a fringe de­vel­oper plat­form. Stack Overflow 2025 (49,000+ re­spon­dents, 177 coun­tries): Ubuntu pri­mary OS for 27.7% of pro­fes­sional de­vel­op­ers. StatCounter: India desk­top Linux 16.21% (July 2024); US crossed 5% in June 2025.

Proposed Solution

Publish an of­fi­cial Claude Desktop build for Linux, tar­get­ing the two cur­rent Ubuntu LTS re­leases (and Debian) as a signed .deb via an Anthropic-operated apt repos­i­tory, us­ing the same dis­tri­b­u­tion pipeline Claude Code al­ready uses for Linux.

Alternative Solutions

Claude Code CLI: of­fi­cial and runs na­tively on Linux with signed apt/​dnf/​apk repos­i­to­ries. Excellent for ter­mi­nal work­flows and runs lo­cal MCP servers fine. Not a sub­sti­tute for the desk­top GUI: no sur­face for test­ing Claude Code plu­g­ins as desk­top ex­ten­sions, no com­puter use, no Cowork.

Web client (claude.ai): sup­ports re­mote MCP con­nec­tors but no desk­top ex­ten­sions, no com­puter use, no Cowork. Loses con­ver­sa­tion state on browser crash; higher RAM and bat­tery cost than a na­tive client.

Community repack­ages (aaddrick/claude-desktop-debian, johnz­fitch/​claude-cowork-linux, Snap wrap­pers, k3d3 NixOS flake): func­tional and what I cur­rently use. Unofficial, not ven­dor-signed, not ven­dor-au­dited.

Windows build un­der Wine: clip­board and font in­te­gra­tion break, MCP sub­process han­dling is un­re­li­able, no first-party se­cu­rity up­dates.

Switching to ma­cOS or Windows to test plu­g­ins: cur­rent workaround. Friction on every it­er­a­tion; not a real fix.

Priority

High - Significant im­pact on pro­duc­tiv­ity

Feature Category

Developer tools/​SDK

Use Case Example

I run Ubuntu LTS as my pri­mary de­vel­op­ment en­vi­ron­ment. Per the Stack Overflow 2025 Developer Survey, this is the case for 27.7% of pro­fes­sional de­vel­op­ers.

I run Ubuntu LTS as my pri­mary de­vel­op­ment en­vi­ron­ment. Per the Stack Overflow 2025 Developer Survey, this is the case for 27.7% of pro­fes­sional de­vel­op­ers.

I de­velop Claude Code plu­g­ins. Plugins are tested and it­er­ated on as Claude Desktop ex­ten­sions, which re­quires Claude Desktop. There is no Linux build.

I de­velop Claude Code plu­g­ins. Plugins are tested and it­er­ated on as Claude Desktop ex­ten­sions, which re­quires Claude Desktop. There is no Linux build.

The cur­rent workaround is to switch to ma­cOS every time I need to test a plu­gin as an ex­ten­sion. This is fric­tion on every it­er­a­tion of a plu­gin I am build­ing on Linux, and a suf­fi­ciently bad er­gonomic that it dis­cour­ages plu­gin de­vel­op­ment from Linux en­tirely.

The cur­rent workaround is to switch to ma­cOS every time I need to test a plu­gin as an ex­ten­sion. This is fric­tion on every it­er­a­tion of a plu­gin I am build­ing on Linux, and a suf­fi­ciently bad er­gonomic that it dis­cour­ages plu­gin de­vel­op­ment from Linux en­tirely.

With an of­fi­cial Linux build I would in­stall via apt from an Anthropic-signed repos­i­tory and de­velop, test and it­er­ate on Claude Code plu­g­ins as desk­top ex­ten­sions on the same ma­chine I write them on.

With an of­fi­cial Linux build I would in­stall via apt from an Anthropic-signed repos­i­tory and de­velop, test and it­er­ate on Claude Code plu­g­ins as desk­top ex­ten­sions on the same ma­chine I write them on.

Additional Context

Sources for the load-bear­ing claims, named pri­mary where pos­si­ble.

Platform sup­port ma­trix

claude.com/​down­load: Not avail­able for Linux”.

code.claude.com/​docs/​en/​desk­top: desk­top app avail­able for ma­cOS and Windows.

Claude Code al­ready on Linux

code.claude.com/​docs/​en/​setup: signed apt, dnf and apk repos­i­to­ries; per-plat­form bi­na­ries (linux-x64, linux-ar­m64, linux-x64-musl, linux-ar­m64-musl); Ubuntu 20.04+/Debian 10+.

Cowork Linux-VM ar­chi­tec­ture

Simon Willison, First im­pres­sions of Claude Cowork”, 12/01/2026 (simonwillison.net): VZVirtualMachine via Apple’s Virtualization Framework boot­ing a cus­tom Linux root filesys­tem.

Simon Willison, First im­pres­sions of Claude Cowork”, 12/01/2026 (simonwillison.net): VZVirtualMachine via Apple’s Virtualization Framework boot­ing a cus­tom Linux root filesys­tem.

Pluto Security: cor­rob­o­rat­ing re­verse-en­gi­neer­ing deep dive, Ubuntu 22.04 in­side the VM.

Pluto Security: cor­rob­o­rat­ing re­verse-en­gi­neer­ing deep dive, Ubuntu 22.04 in­side the VM.

pvieito, Inside Claude Cowork”: ma­cOS host → Apple Virtualization Framework → Ubuntu 22.04 VM → bub­blewrap → sec­comp → Claude Code at /usr/local/bin/claude.

pvieito, Inside Claude Cowork”: ma­cOS host → Apple Virtualization Framework → Ubuntu 22.04 VM → bub­blewrap → sec­comp → Claude Code at /usr/local/bin/claude.

Anthropic doc­u­men­ta­tion con­firms the hy­per­vi­sor split (Apple Virtualization.framework on ma­cOS, Hyper-V on Windows) with­out con­firm­ing the re­verse-en­gi­neered in­ter­nals.

Anthropic doc­u­men­ta­tion con­firms the hy­per­vi­sor split (Apple Virtualization.framework on ma­cOS, Hyper-V on Windows) with­out con­firm­ing the re­verse-en­gi­neered in­ter­nals.

johnz­fitch/​claude-cowork-linux: work­ing com­mu­nity port that stubs the ma­cOS na­tive mod­ules and runs Cowork di­rectly on Linux x86_64 with no VM.

johnz­fitch/​claude-cowork-linux: work­ing com­mu­nity port that stubs the ma­cOS na­tive mod­ules and runs Cowork di­rectly on Linux x86_64 with no VM.

Community pack­ag­ing

aad­drick/​claude-desk­top-de­bian: roughly 4.5k stars; .deb, .rpm, AppImage, AUR, Nix; signed apt and dnf repos­i­to­ries at pkg.claude-desk­top-de­bian.dev; lat­est re­lease v2.0.18+claude1.11187.1 dated 05/06/2026; –doctor di­ag­nos­tic; CI-tested; ex­per­i­men­tal Cowork on Linux.

aad­drick/​claude-desk­top-de­bian: roughly 4.5k stars; .deb, .rpm, AppImage, AUR, Nix; signed apt and dnf repos­i­to­ries at pkg.claude-desk­top-de­bian.dev; lat­est re­lease v2.0.18+claude1.11187.1 dated 05/06/2026; –doctor di­ag­nos­tic; CI-tested; ex­per­i­men­tal Cowork on Linux.

Related: aad­drick/​claude-desk­top-arch, emsi/​claude-desk­top, k3d3/​claude-desk­top-linux-flake.

Related: aad­drick/​claude-desk­top-arch, emsi/​claude-desk­top, k3d3/​claude-desk­top-linux-flake.

Demand

StatCounter: India desk­top Linux 16.21% (July 2024); US crossed 5% in June 2025; global ap­prox­i­mately 4.7% in 2025.

If a first-party build is not on the roadmap

A lower-cost fall­back that would ad­dress most of the trust and se­cu­rity con­cerns: a pub­lic state­ment on the in­stall doc­u­men­ta­tion that Linux is not cur­rently planned (with rough hori­zon if any), ac­knowl­edge­ment of a rec­om­mended com­mu­nity pro­ject, a one-off se­cu­rity re­view sum­mary of that pro­ject, and ex­plicit se­cu­rity guid­ance for Linux users on cre­den­tial han­dling and MCP server con­fig­u­ra­tion.

Steelmanned counter-case

The strongest in­ter­nal not now”, so this is­sue in­vites a real con­ver­sa­tion rather than a po­lite close.

Volume does not jus­tify the en­gi­neer­ing tax. Cowork par­ity, Windows hard­en­ing and agent ca­pa­bil­ity work all plau­si­bly out­rank a third desk­top plat­form.

Volume does not jus­tify the en­gi­neer­ing tax. Cowork par­ity, Windows hard­en­ing and agent ca­pa­bil­ity work all plau­si­bly out­rank a third desk­top plat­form.

Linux frag­men­ta­tion cre­ates a dis­pro­por­tion­ate sup­port tax: dis­tros, dis­play servers, sand­box­ing mod­els, graph­ics stacks. The com­mu­nity pro­jec­t’s com­mit log shows the sur­face (AppArmor userns blocks, KDE Plasma SNI races, Wayland HiDPI, eCryptfs path-length fail­ures).

Linux frag­men­ta­tion cre­ates a dis­pro­por­tion­ate sup­port tax: dis­tros, dis­play servers, sand­box­ing mod­els, graph­ics stacks. The com­mu­nity pro­jec­t’s com­mit log shows the sur­face (AppArmor userns blocks, KDE Plasma SNI races, Wayland HiDPI, eCryptfs path-length fail­ures).

Enterprise Linux de­vel­op­ers are largely served by re­mote de­vel­op­ment and the CLI. A desk­top GUI may not un­lock en­ter­prise rev­enue pro­por­tion­ate to its cost.

Enterprise Linux de­vel­op­ers are largely served by re­mote de­vel­op­ment and the CLI. A desk­top GUI may not un­lock en­ter­prise rev­enue pro­por­tion­ate to its cost.

Opportunity cost. Every en­gi­neer-quar­ter on Linux desk­top is a quar­ter not on agent qual­ity, MCP ecosys­tem, Cowork hard­en­ing, or en­ter­prise con­trol planes.

Opportunity cost. Every en­gi­neer-quar­ter on Linux desk­top is a quar­ter not on agent qual­ity, MCP ecosys­tem, Cowork hard­en­ing, or en­ter­prise con­trol planes.

Distribution is non-triv­ial. Signed re­pos, GPG keys, AppImage sign­ing, Snap, AUR, Nix.

Distribution is non-triv­ial. Signed re­pos, GPG keys, AppImage sign­ing, Snap, AUR, Nix.

A rea­son­able se­nior de­ci­sion could weigh these and con­clude not on the cur­rent roadmap”. I would un­der­stand that. What I do not un­der­stand is the ab­sence of any pub­lic po­si­tion at all, and the struc­tural se­cu­rity cost of that si­lence to cur­rent Linux users.

Note on the triage bot

I am aware this is­sue is processed by an au­to­mated triage sys­tem. I have writ­ten it as a sin­gle con­sol­i­dated re­quest with a clear pri­mary ask and a lower-cost fall­back (the good no” path in Additional Context). Please route rather than close if a dif­fer­ent venue is cor­rect; please re­spond rather than close as not planned” with­out a stated ra­tio­nale, be­cause the ab­sence of a stated ra­tio­nale is part of what this is­sue is ask­ing to fix.

Happy to con­tribute and help main­tain.

Building from Zero After Addiction, Prison, and a Felony

gavinray97.github.io

Building from Zero After Addiction, Prison, and a Felony

I spent ages 14 – 16 in a max­i­mum-se­cu­rity ju­ve­nile prison, be­came a felon at 19, lost al­most every­thing to ad­dic­tion, and later re­built my life through soft­ware, open source, and a few peo­ple who took a chance on me.

I’ve wanted to write this for a while, but kept find­ing rea­sons not to. It felt too per­sonal, too risky, and too easy to mis­read.

Recently, I de­cided on two things:

After see­ing Preston Thorpe speak pub­licly about his own back­ground, I won­dered how many oth­ers like us were silently lurk­ing in tech

I’m far enough in my ca­reer with enough con­tri­bu­tions to OSS and com­mu­nity in­volve­ment, that I think I’ll prob­a­bly be al­right

I wrote this for any­one qui­etly won­der­ing whether they have no chance at a fu­ture.

Below is the much-con­densed life story of my strug­gles with ad­dic­tion, poverty, and in­car­cer­a­tion + life af­ter be­ing a felon. My hope is that it serves as en­cour­age­ment to oth­ers who are in sim­i­lar cir­cum­stances that things CAN get bet­ter.

Amphetamine Addict and Prison at 14

I was a model stu­dent up un­til around pu­berty and mid­dle school. Then, I think a com­bi­na­tion of be­ing bul­lied for be­ing over­weight and teenage hor­mones, led me to be just the wrong com­bi­na­tion of re­sent­ful, an­gry, un­happy, and re­bel­lious.

I started get­ting in fist­fights with peo­ple that made fun of me, be­ing a huge ass­hole to teach­ers, stopped do­ing school­work, and started ex­per­i­ment­ing with drugs.

The be­gin­ning of the end: The day I bought an Adderall from a class­mate. When that am­phet­a­mine feel­ing kicked-in, it was as if life was per­fect for the first time. I was happy, con­fi­dent, felt I could do any­thing. I wanted to feel this way every wak­ing mo­ment for the rest of my life.

Being 14, I had no job, and I do not come from money. So, log­i­cally, I did the thing one must do if one wishes to sus­tain a drug habit: Devise a way to make money.

The eas­i­est way to make money at 14 turned out to be deal­ing drugs, so I started sell­ing var­i­ous pre­scrip­tion med­ica­tions on a buy-low-sell-high” ba­sis from other stu­dents at school.

This was short-lived, as I had the huge mouth of a re­bel­lious I’m in­vin­ci­ble” 14-year old boy, and I was shortly ar­rested and charged with 17 counts of Possession with Intent to Manufacture or Distribute a Scheduled II Controlled Substance.

I wound up spend­ing 2 years, from 14 – 16 at a max­i­mum se­cu­rity ju­ve­nile prison (Lookout Mountain YSC, Golden CO).

Freedom - Shortly Lived

In prison, I got my GED, and af­ter re­lease briefly en­rolled in com­mu­nity col­lege. I was work­ing as a land­scaper do­ing man­ual la­bor for $8/hr and then rid­ing a bus 1hr each way to night classes. Not to say this sort of thing can’t be done (people do it all the time), but I did­n’t have the tenac­ity or mo­ti­va­tion to keep it up, so I dropped out.

I stayed sober for a brief pe­riod be­tween 16 – 17. Not hav­ing learned my les­son, I again started sell­ing drugs. I had learned about The Silk Road and the Darknet and was or­der­ing (what was then) a le­gal Research Chemical” with ef­fects sim­i­lar to MDMA (Methylone/bk-MDMA) shipped to my par­ents house. Eventually, my dad got home early from work and in­ter­cepted a pack­age. Asking me what it was be­fore I left for work, I told him I don’t know, never heard of the re­turn ad­dress name”. My fa­ther was not an id­iot; he told me he was go­ing to open it while I was at work, so I con­fessed it’s drugs.”

Cue huge ar­gu­ment, him in­sist­ing he was go­ing to re­move every­thing from my room ex­cept my clothes and bed (most of which I paid for my­self) and I would not be al­lowed to leave ex­cept for work. This was not an agree­able cir­cum­stance to me, so I re­fused — at which point my dad said then you won’t be liv­ing here any­more!”.

It’s im­por­tant to note that in Colorado (at the time, at least), eman­ci­pa­tion of a mi­nor was not a sta­tus one could file for, but in­stead purely a court sta­tus to be rec­og­nized dur­ing le­gal pro­ceed­ings. That meant there was tech­ni­cally no av­enue for me to legally move out be­fore 18 with proper le­gal sta­tus.

So this, to me, sounded like sweet free­dom & re­lease, rather than a pun­ish­ment. You re­ally won’t call the po­lice if I leave?” Nope.” I packed my back­pack with my lap­top and cash sav­ings, and a suit­case with my clothes, and left. I had no plan but that was a bridge to be crossed.

It turned out that the par­ents of a friend had an un­used bed­room in their trailer they would rent to me un­der-the-table for $300/mo. I jumped at that and slept on the floor of a trailer for 6 months.

I worked as a land­scaper, at a lum­ber mill, and as a cashier at Walgreens, con­tin­u­ing to sell drugs on the side.

Inevitably, I wound up be­ing ar­rested again on drug-re­lated charges, and spent 18 – 19 in county jail. It was then that I be­came a con­victed felon with a low-class felony.

A Serendipitous News Article & a Software Job

While I was in county jail, one day the news­pa­per had a small ar­ti­cle in it: Tech com­pany of­fers in­tern­ships to at-risk & un­der­priv­i­leged youth”

I had spent my child­hood on the com­puter, play­ing videogames and even­tu­ally teach­ing my­self to pro­gram to make game mods. I knew from a young age I wanted to be a pro­gram­mer (I thought I wanted to make videogames, as most young chil­dren do).

This to me, seemed like a for­tu­itous op­por­tu­nity. I cut the ar­ti­cle out and put it in a doc­u­ments folder.

Eventually, I was moved from reg­u­lar jail pop­u­la­tion into the Work-Release jail pro­gram, where they let you out dur­ing the day for work. You had 1 week to find a job, and if you could­n’t se­cure em­ploy­ment you were sent back per­ma­nently to fin­ish out your sen­tence.

The first day out, I walked into the of­fices of the com­pany from the ar­ti­cle and asked to speak to some­one. I ex­plained that I was fresh out of jail and had seen their ar­ti­cle while in­side.

They in­ter­viewed me, de­cided to hire me, and I was now an in­tern Full-Stack Web Developer! I knew noth­ing of web dev, and did­n’t even par­tic­u­larly have an in­ter­est in it orig­i­nally, but the job was al­ready be­yond my hopes. I had as­sumed I was go­ing to spend the rest of my life work­ing con­struc­tion or sim­i­lar, be­cause of my felony.

The same news re­porter that had done the orig­i­nal ar­ti­cle later came to visit, and af­ter in­ter­view­ing me, did a whole writeup on it!

https://​www.dai­ly­cam­era.com/​2017/​05/​12/​boul­der-tech-acad­e­mies-swamped-as-they-race-to-re­train-work­ers/

Working at Techtonic was the best pos­si­ble early-ca­reer ex­pe­ri­ence I think any­one could have had. They did con­tract de­vel­op­ment, a lot of which was green­field Saas MVP launches, across var­i­ous tech stacks. There was not a lot of time for men­tor­ship so it a very trial-by-fire” ex­pe­ri­ence — ei­ther fig­ure things out and ship stuff, or get the boot.

I learned fron­tend, back­end, and dev-ops while there and worked across sev­eral lan­guages + DBs. This was around the time Ruby on Rails + MongoDB was the hip thing. ES6 JS was still fresh and new, and it was there that our CTO did a com­pany meet­ing on this new thing called React” that we were to start learn­ing to re­place jQuery.

It’s also where I met my now-wife, who I pulled into my drug use and un­sta­ble life.

Drugs, Part 2: Electric Boogaloo

Being pos­si­bly the most hard­headed in­di­vid­ual in the uni­verse, I fell back into drug use shortly there­after. I man­aged to re­main mostly-func­tional, un­til the man­ager at Techtonic (who did not like me) lied to the owner that I was show­ing up hours late every day.

She fired me (and my now-wife), and I was later re­deemed when they found the truth in his Slack mes­sage his­tory af­ter fir­ing him many moons later. But oh whale, them’s the breaks”, as they say.

Not hav­ing a job, I spi­raled harder into ad­dic­tion, and even­tu­ally ran out of money to pay my rent and bills. We moved in with my bi­o­log­i­cal fa­ther in Florida. He was also an ad­dict, and in­stead of sta­bil­ity, the sit­u­a­tion be­came en­abling and de­struc­tive. It ex­ploded in short or­der.

From Zero

After the liv­ing sit­u­a­tion with my fa­ther ex­ploded, I was for­tu­nate enough to have a friend who had a spare room in the house and agreed to let me and my (now wife) stay with them for some tiny sum of money, but only tem­porar­ily un­til we could find work + save enough to move out and get back on our feet.

It was at this point we had noth­ing: A few dol­lars to our name, no ve­hi­cle, some cloth­ing and a sin­gle lap­top.

I had lost every­thing. And I had dragged this poor woman into it with me who had lost every­thing, too.

It was at this point my so­bri­ety be­gan. I had hit what we ad­dicts call a bot­tom”. Not the first one, but the one that was fi­nally grim and bleak enough to make me look at my­self and go What the fuck are you do­ing?” The one that fi­nally knocked it into my skull that I did­n’t want to live like this any­more.

I started wash­ing dishes at a restau­rant, and my wife took a job de­liv­er­ing and in­stalling large ap­pli­ances (ovens, fridges, etc) at the same ware­house where the friend worked. Having no ve­hi­cle, she had to bor­row the friend’s bi­cy­cle and ride 30 min­utes in the dark be­fore work, and 30 min­utes in the swel­ter­ing heat af­ter work home. The hours were very long, be­cause it was of­ten on-site in­stal­la­tion paid by the ap­pli­ance, so many days she would work 10 – 12 hours + 1 hour bike ride, and come home so ex­hausted all she could do was sob a lit­tle be­fore get­ting just enough sleep to do it all over again the next day.

Eventually, she told me that it made more sense for me to quit my job while she worked, so that I could spend all of my free time try­ing to get an­other tech job. So she alone car­ried us for sev­eral months. I sent out hun­dreds of ap­pli­ca­tions. I went through fi­nal-round in­ter­views and re­ceived of­fer let­ters from 8 com­pa­nies, only to have them re­scinded each time due to cor­po­rate No Felons” HR poli­cies. It was like hav­ing the car­rot dan­gled right in front of my face, to be snatched away each time.

Finally, I got an in­ter­view with a tiny startup in Miami. I passed their phone screen, and drove 4 hours each way to do the in-per­son.

They of­fered me the job, and helped pay for us to re­lo­cate and tem­porar­ily stay in Airbnb’s. It paid $50k, with the promise of a sig­nif­i­cant raise in 1 year when the com­pany had more rev­enue. I was over­joyed with the of­fer and im­me­di­ately ac­cepted.

Hasura, Open Source, and the Door That Stayed Open

The sys­tem at work was an age­ing Rails app that had ac­crued sig­nif­i­cant tech debt and was the re­sult of an amal­gam of out­sourced de­vel­op­ment shops. One of them was clearly quite pro­fi­cient, and the oth­ers… not so much. Part of my job was de­sign­ing and im­ple­ment­ing a V2 rewrite. While eval­u­at­ing tech­nolo­gies for this, I stum­bled upon Hasura

https://​github.com/​ha­sura/​graphql-en­gine

Put sim­ply, it au­to­mated the work of gen­er­at­ing CRUD for Postgres apps, and was de­signed by peo­ple who clearly had hit the lim­i­ta­tions of tra­di­tional Backend-as-a-Service type plat­forms. Only core CRUD was au­to­mated, and you in­te­grated the rest of your app through wiring up your own API end­points and im­ple­ment­ing your own AuthN + AuthZ.

The first time I plugged in our lo­cal­host Postgres URL for dev, and had a full work­ing CRUD API, I was hooked. Coming from a back­ground of rapidly churn­ing out SaaS MVPs, this was solv­ing a very real prob­lem for me, and it was PERFORMANT.

I be­came heav­ily in­volved in the Discord server, an­swer­ing other peo­ple’s ques­tions, and also started send­ing PRs to im­ple­ment fea­tures I felt were miss­ing.

When my 1 year an­niver­sary came around at work, the founders un­for­tu­nately still were not in a po­si­tion to pay me much more. I knew the fi­nan­cials of the busi­ness and they weren’t ly­ing, but it was still some­what of a dis­ap­point­ment. One of the Hasura em­ploy­ees had re­cently made a joke that I should just ap­ply to work there. I fig­ured that it could­n’t hurt to at least get more info.

I went through the in­ter­view rounds more as a for­mal­ity and was given an of­fer let­ter. I was of­fered slightly more than dou­ble my cur­rent salary! I gen­uinely loved work­ing with the founders at my cur­rent job and felt ter­ri­ble about leav­ing, but I did ac­cept the of­fer and stay on for an­other month to fin­ish up cur­rent work and make sure there was some­one to hand off to.

The com­pany was so small back then that there was no back­ground check done dur­ing the in­ter­view process. After work­ing there a while, I even­tu­ally dis­closed to the Hasura founders that I had a low-grade felony, and, thank the stars, they were cool with it.

I had my dream job: Working on a de­vel­oper-fac­ing tool I gen­uinely loved and was a power-user of, that was also part of the Postgres ecosys­tem. I could not have con­ceived of such a per­fectly-fit po­si­tion. I have been work­ing at Hasura (now PromptQL) since 2020, and I plan on rid­ing this one all the way to it’s end: ei­ther fired, bank­rupt, or bought-out. (Hopefully bought-out).

Conclusion

I don’t tell this story be­cause I think it is clean, heroic, or uni­ver­sally ap­plic­a­ble — It is­n’t. I made TERRIBLE choices. I hurt peo­ple who loved me. I wasted chances that other peo­ple would have killed for. And even when I fi­nally started do­ing the right things, I still needed luck, help, tim­ing, for­give­ness, and peo­ple will­ing to judge me by what I could do next in­stead of only by what I had done be­fore.

But that is ex­actly why I wanted to write this.

If you are read­ing this from the mid­dle of ad­dic­tion, poverty, a crim­i­nal record, or some other hole that feels per­ma­nent: I won’t in­sult you by claim­ing it’s easy. It may be un­fair for a long time. You may have to hear no” from peo­ple who never even look at your work. You may have to re­build with less room for mis­take than every­one around you.

But you are not nec­es­sar­ily fin­ished.

And if you are in a po­si­tion to hire, men­tor, re­view pull re­quests, or let some­one into a room they nor­mally would not be al­lowed into: please re­mem­ber that tal­ent is not evenly dis­trib­uted by back­ground check. Sometimes the per­son who looks risky on pa­per is also the per­son who will spend years try­ing to be­come wor­thy of the chance they were given.

I am alive, sober, mar­ried, em­ployed, and work­ing on soft­ware I care about be­cause a hand­ful of peo­ple took that risk on me.

I wake up grate­ful for that every day. And I hope, over time, to be­come the kind of per­son who gives that same chance to some­one else.

AI Use Disclaimer: claude code was used to gen­er­ate the OpenGraph SVG im­age.

No part of the prose was ma­chine-gen­er­ated. You will not find ma­chine-writ­ten prose on this blog. I con­sider it deeply dis­re­spect­ful.

2025 - The 29th IOCCC

www.ioccc.org

Twenty Ninth International Obfuscated C Code Contest

Where to start

See be­low for links to the 2025 win­ning IOCCC en­tries.

Check out the in­dex.html web pages for each win­ning en­try. They have most of the in­for­ma­tion you need to com­pile and run the win­ning pro­gram. Take a look at the win­ning source code and try to fig­ure out how it works. You might also want to check out the au­thor’s re­marks for even more de­tails.

You may down­load all win­ning en­tries in the form of a com­pressed tar­ball for this year’s con­test.

For IOCCC29, the vol­ume and qual­ity of sub­mis­sions were at near-his­toric heights.

IOCCC28 was spec­u­lated to have at­tracted a record num­ber of sub­mis­sions due to the 4-year ab­sence, al­low­ing au­thors to re­fine their sub­mis­sions, re­sult­ing in a higher-than-usual sub­mis­sion qual­ity.

IOCCC29 was the sec­ond con­sec­u­tive con­test af­ter the 2020 – 2024 hia­tus. And yet, the num­ber of sub­mis­sions for IOCCC29 was sim­i­lar to last year’s con­test, and the over­all sub­mis­sion qual­ity re­mained high for this con­test. So per­haps the in­creased sub­mis­sion vol­ume, com­bined with a higher-than-usual sub­mis­sion qual­ity, is due to fac­tors such as im­proved web­site de­sign, in­creased so­cial me­dia pres­ence, au­thors build­ing on the ideas of past win­ning en­tries, and other fac­tors?

Starting with the close of IOCCC28, the pro­ce­dures used for clos­ing the con­test to new sub­mis­sions, the judg­ing process, se­lect­ing the win­ning en­tries, prepar­ing the up­date to the web­site, and the process to cre­ate the live show on the Our Favorite Universe were care­fully doc­u­mented. And while this doc­u­men­ta­tion re­quired ad­di­tional time as well as more ef­fort, the doc­u­men­ta­tion process re­sulted in over­all im­prove­ments to how the IOCCC is run.

A few days af­ter the pre­sen­ta­tion of the win­ning en­tries for IOCCC29 has been made on the Our Favorite Universe YouTube chan­nel. The record­ing of the main show will be di­vided up into in­di­vid­ual seg­ments. Then, each win­ning en­try will be up­dated to in­clude a link to a YouTube seg­ment un­der a new Award pre­sen­ta­tion near the top of the win­ning en­try’s in­dex.html page.

Fun chal­lenge info

We have added fun chal­lenges to this year’s win­ning en­tries com­pe­ti­tion, un­der the Judges’ re­marks” sec­tion. After you fig­ure out what a given win­ning en­try does, we en­cour­age you to at­tempt the fun chal­lenge.

Some of these chal­lenges are eas­ier than oth­ers. In some cases, you’re asked to cre­ate an al­ter­na­tive ver­sion of prog.c or a re­lated file. In some cases you are asked to pro­duce an ex­pla­na­tion about some­thing.

If the fun chal­lenge is still open (check the A fun chal­lenge” sec­tion for the given win­ning en­try), con­sider sub­mit­ting a GitHub pull re­quest as a con­tri­bu­tion.

If the fun chal­lenge is closed, but you think you have a bet­ter so­lu­tion, con­sider sub­mit­ting a GitHub pull re­quest as a con­tri­bu­tion. If the IOCCC Judges agree that you so­lu­tion is bet­ter, we will con­sider it.

If you be­lieve you have an even bet­ter (or im­prove­ment) to win­ning en­try’s fun chal­lenge, please con­sider sub­mit­ting a GitHub pull re­quest, for the IOCCC judges to con­sider.

Rules and Guidelines for this con­test

The fi­nal ver­sions of the IOCCC rules and guide­lines that were in ef­fect for this con­test were:

2025 rules ver­sion 29.15 2025 – 12-02

2025 guide­lines ver­sion 29.08 2025 – 12-02

The IOCCC rules and guide­lines for IOCCC29 rep­re­sented a sub­stan­tial rewrite over pre­vi­ous con­tests, thanks in part to a num­ber of vol­un­teers: giv­ing the IOCCC judges use­ful ed­its, text rewrites, con­sol­i­da­tion, as well as over­all im­proved or­ga­ni­za­tion.

Looking for­ward to the next con­test

We plan to open IOCCC30 to­wards the end of 2026 and have the con­test run for a sim­i­lar amount of time, clos­ing some­time to­wards the end of Q1 2027.

As we per­form the ac­tions needed to open IOCCC30, we plan to in­ter­nally doc­u­ment the process as we did dur­ing the clos­ing of IOCCC29.

About two or three weeks af­ter the IOCCC29 win­ning en­tries have been posted, and we process some of the early pull re­quests against the 2025 di­rec­tory tree, the IOCCC Judges plan to go on an IOCCC va­ca­tion.

We had in­tended to go on an IOCCC va­ca­tion af­ter re­leas­ing the win­ners of IOCCC28, but then the ef­forts to process bug fixes and en­hance­ments to the mkioc­c­cen­try repo took so much time that by the time that repo was sta­ble, it was time to open IOCCC29. Therefore, this time, we plan to wait un­til af­ter the end of our post-IOC­C­C29 IOCCC va­ca­tion be­fore work­ing on any mkioc­c­cen­try repo PRs.

While work­ing on cre­at­ing po­ten­tial write-ups for sub­mis­sions that en­tered the fi­nal round of the set of judg­ing rounds:

A few sub­mis­sions were set aside in the fi­nal round of the fi­nal set of rounds.

We gained an ad­di­tional level of ap­pre­ci­a­tion for a num­ber of the re­main­ing en­tries.

While the win­ning en­try au­thors came from lo­ca­tions of pre­vi­ous win­ning au­thors, this IOCCC29 had an au­thor - jing­p49 from a new lo­ca­tion: Taiwan.

This con­test saw a Hat trick of Hat-tricks by:

Yusuke Endoh: 2025/endoh1, 2025/endoh2, and 2025/endoh3

Nick Craig-Wood: 2025/ncw1, 2025/ncw2, and 2025/ncw3

Don Yang: 2025/yang1, 2025/yang2, and 2025/yang3

Notable and re­mark­able win­ning en­tries of IOCCC29 in­clude, but are not lim­ited to:

2025/cable - Subleq com­puter

2025/cesmoak - Black hole punch­card Fortran

2025/endoh3 - patch/​diff quine

2025/jhshrvdp - Quasi-rogue-like game

2025/jingp49 - Dr. WHO se­quence

2025/ncw1 - GameBoy em­u­la­tor

2025/tompng - Ocean sound gen­er­a­tor

2025/uellenberg - Quine pong

2025/yang2 - Zoltraak en­cod­ing

Those are just a few of the many amaz­ing win­ners of the IOCCC29, so be sure to check out the rest!

As we dis­cussed above, there were quite a few ex­cel­lent sub­mis­sions that did­n’t quite make the fi­nal cut. We truly ap­pre­ci­ate the hard work each au­thor put into their en­tries, but we’re sorry that we can’t award based solely on ef­fort.

We re­ceived many great sub­mis­sions that did­n’t quite make the cut as win­ners. If you sub­mit­ted some­thing for IOCCC29 that did­n’t win, think about pol­ish­ing your code and giv­ing it an­other shot for IOCCC30. Interestingly, more than one win­ner of IOCCC29 was ac­tu­ally an im­proved ver­sion of code that did­n’t win in a pre­vi­ous con­test.

Encouragement for those who did not win this year

We know many of you that sub­mit­ted to the IOCCC put in a ton of ef­fort into your sub­mis­sions for this year’s IOCCC. We can’t just give out awards to every­one. That would mean tak­ing away from the sub­mis­sions that we think are the best and de­serve to win.

Sometimes, a fi­nal round sub­mis­sion might be good enough to be a win­ning IOCCC en­try, only to be beaten by a sim­i­lar, but slightly bet­ter sub­mis­sion. If you think this hap­pened with your sub­mis­sion, con­sider sub­mit­ting an en­hanced ver­sion to the next IOCCC.

PLEASE DO NOT give up hope! There are some sub­mis­sions that have been sub­mit­ted with re­vi­sions, mul­ti­ple times be­fore ris­ing to the level of a win­ning IOCCC en­try. You might also want to try with a dif­fer­ent type of sub­mis­sion al­to­gether for the next IOCCC.

If you’re not plan­ning to im­prove and re­sub­mit your non-win­ning en­try for the next IOCCC, you’re wel­come to pub­lish it.

On com­pil­ing and run­ning win­ning en­tries

Some C com­pil­ers aren’t as great as they could be. If yours is­n’t work­ing well, you might want to try com­pil­ing with an up­dated ver­sion of clang and/​or gcc in­stead.

If you en­counter prob­lems in com­pil­ing and/​or run­ning the win­ning en­tries, see the FAQ on:

Compiling IOCCC en­tries

IOCCC en­try de­pen­den­cies

Problems com­pil­ing en­tries

Running IOCCC en­tries

For ad­di­tional in­for­ma­tion on how to sub­mit fixes, see the FAQ on:

How to sub­mit a fix - how to sub­mit a fix to an en­try

Update au­thor in­for­ma­tion - how to cor­rect or up­date an IOCCC au­thor’s in­for­ma­tion

For even more in­for­ma­tion

Reporting an IOCCC web­site prob­lem

Submitting a fix to the IOCCC web­site

How to con­tact the IOCCC - up-to-date con­tact de­tails

IOCCC FAQ - ad­di­tional in­for­ma­tion on the IOCCC

www.ioccc.org - the pri­mary IOCCC web­site

Winning Entries of 2025 - The 29th IOCCC

Download all win­ning en­tries from 2025

2025/ayu - IMO award

2025/cable - Best imag­i­nary em­u­la­tor

2025/cesmoak - Retro space award

2025/diels-grabsch - Best one liner

2025/dogon - Consistently con­stant award

2025/endoh1 - Most likely to daz­zle

2025/endoh2 - Most likely to shock

2025/endoh3 - Most re­silient

2025/ferguson - Opposite award

2025/howe - Most likely to in­vade

2025/jhshrvdp - Most likely to tele­port

2025/jingp49 - Who won award

2025/kurdyukov - Most likely to count

2025/mattpep - Most ob­fus­cated op­tions

2025/ncw1 - Best real em­u­la­tor

2025/ncw2 - Best frac­tional em­u­la­tor

2025/ncw3 - Best use of Unicode

2025/tompng - Most sooth­ing

2025/uellenberg - Ping pong prize

2025/yang1 - Compound prize

2025/yang2 - Most mag­i­cal word

2025/yang3 - INABIAF award

Jump to: top

Scientists ejected from diabetes conference for distributing journal reprints

arstechnica.com

Five lead­ing sci­en­tists were ousted from the an­nual meet­ing of the American Diabetes Association (ADA) in New Orleans on Friday. Their crime: hand­ing out copies of an ed­i­to­r­ial, pub­lished in the jour­nal Diabetes Care on April 29, sharply crit­i­ciz­ing the Trump ad­min­is­tra­tion’s on­go­ing at­tacks on sci­en­tific re­search.

Those ousted were Steven Kahn, pro­fes­sor of med­i­cine at the University of Washington and ed­i­tor-in-chief of Diabetes Care, who co-au­thored the pub­lished ed­i­to­r­ial; for­mer ADA pres­i­dent Desmond Schatz of the University of Florida, Gainesville; Aaron Kelly, pe­di­atrics pro­fes­sor at the University of Minnesota; Justin Ryder of Northwestern University; and Irl Hirsch, also of the University of Washington. The five were hand­ing out reprints of the ed­i­to­r­ial out­side a room where NIH di­rec­tor Jay Bhattacharya had been sched­uled to speak. Bhattacharya can­celled and an­other NIH of­fi­cial spoke in his stead.

They phys­i­cally grabbed us, forced us out of the con­fer­ence cen­ter, and now are telling us we can no longer at­tend this meet­ing,” Kelly told MedPage Today, which first re­ported the in­ci­dent. They’re tak­ing our lan­yards. It re­ally has come to this in America. Censorship is real. America needs to stand up. Scientists, stand up. Physicians, stand up.”

The ADA con­firmed to MedPage Today that five reg­is­tered sci­en­tists had been re­moved from the meet­ing, claim­ing the sci­en­tists had vi­o­lated the or­ga­ni­za­tion’s code of con­duct for con­fer­ences. These at­ten­dees were es­corted out by our on­site event se­cu­rity be­cause they demon­strated be­hav­ior not con­sis­tent with this code of con­duct,” the ADA me­dia team said in a state­ment. They were re­spect­fully given the op­por­tu­nity to cease this be­hav­ior and chose not to which is why they were es­corted out.”

All at­ten­dees will con­duct them­selves in a pro­fes­sional and re­spect­ful man­ner, free from any form of dis­crim­i­na­tion, ha­rass­ment, or in­tim­i­da­tion,” the code of con­duct states. Inappropriate con­duct, in­clud­ing but not lim­ited to ha­rass­ment; threat­en­ing or un­wel­come phys­i­cal or ver­bal ac­tions; or dis­or­derly or dis­rup­tive con­duct such as protest­ing, will not be tol­er­ated.”

How's Linear so fast? A technical breakdown

performance.dev

Dennis BrotzkyMay 3, 2026

A few mil­lisec­onds is all it takes to up­date an is­sue in Linear. A tra­di­tional CRUD app do­ing the same thing takes about 300ms. How do they do it? There’s no se­cret sil­ver bul­let to per­for­mance. The re­al­ity is that it’s built from the ground up on the right foun­da­tion, then im­proved by count­less de­ci­sions. My goal is to walk through some of the tech­niques that make Linear feel the way it does and help you im­ple­ment the same.

What I’ll cover

Database in the browser

Database in the browser

Making the first load feel in­stant

Making the first load feel in­stant

The sync en­gine

The sync en­gine

Designed for speed

Designed for speed

Animations

Animations

A quick dis­claimer: I’ve never worked at Linear and have never seen their code. Everything I share comes from my per­sonal ex­pe­ri­ence, study­ing their app, read­ing their blog posts, or watch­ing their con­fer­ence talks. I sim­ply love build­ing web apps and have been us­ing Linear since their beta launch. Also, the ar­ti­cle’s hero im­age comes from a video by Meg Wayne, whose work for Linear is phe­nom­e­nal.

Database in the browser

Most web apps live in­side the same loop. The user clicks. The browser fires an HTTP re­quest. A server queries a data­base and sends it back. The browser re­paints. The end re­sult is a spin­ner, a skele­ton, or a frozen UI for a few hun­dred mil­lisec­onds while the app waits on the net­work.

Linear in­verts the tra­di­tional re­la­tion­ship. The ac­tual data­base the UI reads from is in the browser, in IndexedDB. Mutations ap­ply lo­cally first, then asyn­chro­nously push to the server, which broad­casts deltas back to other clients via WebSocket.

In my opin­ion, this is the most crit­i­cal piece to Linear’s per­for­mance. When your goal is to build a fast web app the biggest bot­tle­neck you will fight is the net­work. Any data sent be­tween the client and server costs hun­dreds of mil­lisec­onds. The best ap­proach is to elim­i­nate the need for a net­work re­quest en­tirely: which is ex­actly what Linear does.

I’ll be re­peat­ing this a lot, but the se­cret to build­ing in­cred­i­ble web apps is by hid­ing all the net­work re­quests from the user. The more load­ing states you can avoid the bet­ter.

Here’s an ex­am­ple of how sim­ple Linear’s re­quests are:

// A tra­di­tional web app up­dat­ing the server async func­tion up­dateIs­sue({ is­sue }) { showSpin­ner(); const re­sponse = await fetch(`/​api/​is­sues/${​is­sue.id}`, { method: PATCH, body: JSON.stringify({ ti­tle: is­sue.ti­tle }), }); const up­dated = await re­sponse.json(); setIs­sue(up­dated) hideSpin­ner(); }

// vs Linear is­sue.ti­tle = Faster app launch”; is­sue.save();

The first line, is­sue.ti­tle = Faster app launch”, up­dates an in-mem­ory data­s­tore (MobX ob­serv­able in Linear’s case) . The sec­ond line, is­sue.save();, queues a trans­ac­tion that their sync en­gine batches and flushes to the server. The key here is that the UI re-ren­ders syn­chro­nously off the lo­cal, in-mem­ory, up­date. There are no spin­ners be­cause there is noth­ing to wait for be­cause the data is synced in the back­round. This is the magic of treat­ing the browser as the data­base for each user.

Tuomas, one of Linear’s co-founders, said this at a con­fer­ence in 2024: Literally the first lines of code that I wrote was the sync en­gine, which is very un­com­mon to what you usu­ally do when you’re a startup.’ From day one, Linear knew the ap­proach they wanted to take and the trade­offs it would take.

I know most peo­ple won’t build a cus­tom sync en­gine like Linear just to make their app feel fast and they don’t need to. For most use cases, li­braries like Tanstack Query and SWR can get sur­pris­ingly close with op­ti­mistic up­dates. Most web apps feel slow be­cause the UI waits for each net­work re­quest to com­plete be­fore up­dat­ing state. For most use­cases the net­work re­quest will suc­ceed so you should take ad­van­tage of that and op­ti­misti­cally up­date your state.

// op­ti­mistic mu­ta­tion with SWR mu­tate( `/api/issues/${issue.id}`, { …issue, ti­tle: Faster app launch” }, false );

// vs Linear is­sue.ti­tle = Faster app launch”; is­sue.save();

The key idea is sim­ple: UI re­spon­sive­ness should not de­pend on net­work la­tency. Users per­ceive speed based on how quickly the in­ter­face re­acts, not how quickly the server re­sponds.

Optmistic re­quests is one of the high­est lever­age im­prove­ments you can make:

elim­i­nate un­nec­es­sary spin­ners

elim­i­nate un­nec­es­sary spin­ners

up­date state im­me­di­ately

up­date state im­me­di­ately

val­i­date in the back­ground

val­i­date in the back­ground

roll­back only if needed

roll­back only if needed

Linear’s foun­da­tion is based on this ex­act prin­ci­pal and it makes the app feel na­tive and fast.

A peek into Linear’s stack

Linear is built on the sim­plest stacks you can find: React, TypeScript, MobX, Postgres, a CDN. There’s no edge data­base, no React Server Components, or no fancy frame­work.

Frontend React + re­act-dom (UI run­time) MobX (observable graph, gran­u­lar re-ren­ders) TypeScript (single lan­guage end-to-end) Rolldown-Vite + plu­gin-re­act-oxc(mid-2025; pre­vi­ously Rollup; pre­vi­ously Parcel) ProseMirror + y-pros­emir­ror (rich text ed­i­tor; Yjs CRDT for live col­lab) Radix UI prim­i­tives (popovers, menus, fo­cus traps) Emotion + StyleX (Emotion run­time + StyleX com­piled to atomic CSS) Comlink (Worker RPC) idb (IndexedDB wrap­per back­ing the lo­cal-first store) graphql-re­quest (GraphQL trans­port to the sync server) Sentry (error mon­i­tor­ing) Inter Variable (single woff2, font-dis­play: swap)

Backend Node.js + TypeScript (single lan­guage for all server code) PostgreSQL on Cloud SQL (issues table par­ti­tioned 300 ways) Memorystore Redis (event bus + cache + sync cur­sors) tur­bop­uffer (similar-issue de­tec­tion, vec­tor db) Kubernetes on GCP (one work­load per con­cern) Cloudflare Workers (multi-region edge proxy)

Other clients Desktop: Electron (same web JS, na­tive chrome) Mobile: Swift (iOS) + Kotlin (a sep­a­rate full reim­ple­men­ta­tion)

Marketing Next.js (static) styled-com­po­nents Inline SVG sprite

The biggest stand­out to me is their de­ci­sion to stick with client-side ren­der­ing. CSR of­ten gets crit­i­cized for slow ini­tial loads, but with the right ar­chi­tec­ture and de­sign it can feel in­stant.

I’m also a big fan of the sim­plic­ity it brings. Keeping the app en­tirely client-side cre­ates a much cleaner men­tal model and re­moves a lot of the com­plex­ity that comes with server-ren­dered apps. You don’t have to con­stantly think if you’re on the server or client. If win­dow ob­ject is ac­ces­si­ble or not. If you’re set­ting the right cache head­ers or not. There’s beauty in sim­plic­ity and the con­straints you’re forced into.

So how does Linear make their client side ren­dered app feel in­stant?

Making the first load feel in­stant

One thing I ob­sess over is the first load, and Linear clearly does as well. For pro­duc­tiv­ity tools es­pe­cially, the time it takes be­fore you can ac­tu­ally start work­ing is one of the most im­por­tant de­tails to con­sider. No one wants to be wait­ing for a new tab to load for mul­ti­ple sec­onds

First, you have to un­der­stand what makes ini­tial loads slow. For a client side app you have to re­quest the in­dex.html, then that re­quests all the JavaScript and CSS, which then runs some sort of au­then­ti­ca­tion, and fi­nally makes some API re­quests to show the app.

Linear’s bundler arc: Parcel, Rollup, Vite, Rolldown

The first step to mak­ing an app feel in­stant hap­pens long be­fore run­time. It starts at build time. Remember, the net­work is the bot­tle­neck, so ship­ping the least amount of JavaScript and CSS is crit­i­cal to fast load times.

From what I can gather Linear has rewrit­ten their build pipeline four times: Parcel → Rollup → Vite → Rolldown. Each mi­gra­tion was dri­ven by the same goal: re­duce the amount of JavaScript and CSS and im­prove the de­vel­oper ex­pe­ri­ence.

From their own blog posts they claim:

50% less code shipped.

50% less code shipped.

30% smaller af­ter com­pres­sion.

30% smaller af­ter com­pres­sion.

Cold-cache page loads got 10 to 30% faster.

Cold-cache page loads got 10 to 30% faster.

Time-to-first-paint of the ac­tive-is­sues view dropped 59% (on Safari).

Time-to-first-paint of the ac­tive-is­sues view dropped 59% (on Safari).

Memory us­age dropped 70 to 80%

Memory us­age dropped 70 to 80%

Most of that came from a com­bi­na­tion of de­ci­sions tar­get­ing only mod­ern browsers, bet­ter dead-code elim­i­na­tion, and ag­gres­sive code split­ting. Dropping legacy sup­port is the big win (no poly­fills, no ES5 tran­spi­la­tion, no nomod­ule fall­back) but the dead-code and chunk­ing work mat­ters just as much.

Even with all of these op­ti­miza­tions, Linear still ships a sub­stan­tial amount of code: roughly 21 MB of mini­fied JavaScript. The dif­fer­ence is that it’s ag­gres­sively code split into hun­dreds of route-level chunks that are fetched on de­mand.

// vite.con­fig.ts (reconstruction; matches ob­served chunk graph) ex­port de­fault de­fineCon­fig({ plu­g­ins: [react()], build: { tar­get: esnext”, // no legacy syn­tax, no poly­fills css­Minify: lightningcss”, mod­ulePre­load: { poly­fill: false }, rollupOp­tions: { out­put: { // One chunk per npm pack­age > ~3 KB. Cache in­val­i­da­tion // be­comes per-li­brary in­stead of per-app-re­vi­sion. man­u­alChunks(id) { if (id.includes(“node_modules”)) { const pkg = id.match(/​node_­mod­ules\/([^/]+)/)?.[​1]; if (pkg) re­turn `vendor-${pkg}`; } }, }, }, }, });

The les­son is­n’t which bundler to pick but the im­por­tance of drop­ping legacy browsers, go­ing na­tive ESM, and code split­ting like crazy. Each step is small. Stacked, they cut Linear’s first-load JavaScript roughly in half and their build time by an or­der of mag­ni­tude.

So, the first se­cret to in­stant load times is re­duc­ing the amount of JavaScript and CSS needed to ren­der some­thing for the user.

Preloading af­ter ini­tial load

Once you’ve split your JavaScript into the small­est chunks pos­si­ble you can start do­ing work in the back­ground.

But hold on, split­ting the bun­dle into hun­dreds of chunks cre­ates a new prob­lem. Each chunk im­ports other chunks, and the browser does­n’t know what those are un­til it parses the en­try script. Without help, the load time­line be­comes a wa­ter­fall: fetch the en­try, parse it, fetch its im­ports, parse those, fetch their im­ports. Every level adds a net­work round-trip, which you want to avoid at all costs.

What Linear does is be­fore any JavaScript runs, the browser sees the en­tire list and fires off the re­quests in par­al­lel. By the time the en­try script reaches its first im­port, the chunks are al­ready in cache.

Here’s what it looks like in the <head /> if their in­dex.html

<script type=mod­ule crosso­ri­gin src=“https://​sta­tic.lin­ear.app/​client/​as­sets/​html.2_JBQs3Q.js></script> <link rel=mod­ulepre­load crosso­ri­gin href=“https://​sta­tic.lin­ear.app/​client/​as­sets/​ven­dor-mobx.Crhy2qQc.js> <link rel=mod­ulepre­load crosso­ri­gin href=“https://​sta­tic.lin­ear.app/​client/​as­sets/​SyncWeb­Socket.Djw6l_Op.js> <link rel=mod­ulepre­load crosso­ri­gin href=“https://​sta­tic.lin­ear.app/​client/​as­sets/​Data­base­M­an­ager.DKss­GAN8.js> <!– …around many more –>

The crosso­ri­gin at­tribute on each pre­load matches the crosso­ri­gin on the en­try script, so the browser reuses the cached fetch in­stead of treat­ing pre­load and im­port as sep­a­rate re­sources. Same trick as the font pre­load, ap­plied to every chunk on the crit­i­cal path.

The cold-load time­line col­lapses from a se­quen­tial wa­ter­fall into a sin­gle par­al­lel batch. The net­work still does the work. It just does it all at once. The beauty of this tech­nique is you’re able to do all this work in the back­ground when the user first hits the lo­gin page. In a few sec­onds the full app is stored in cache and served in­stantly.

It’s ex­tremely im­por­tant to un­der­stand how peo­ple will use your app. Once you have this un­der­stand­ing you can start us­ing it to your ad­van­tage, such as pre­load­ing scripts in the back­ground as Linear does.

The ser­vice worker for even more speed and of­fline ca­pa­bil­i­ties

The rest of the Linear, the route-level chunks for views the user has­n’t vis­ited yet, gets cached in the back­ground by a ser­vice worker. The worker has a pre­cache man­i­fest baked into its source, around 1,200 hashed as­sets cov­er­ing route chunks, icons, and fonts, and pulls them down lazily af­ter the first page load. Within a few sec­onds of hit­ting the lo­gin screen, the full app is sit­ting in cache.

This buys two things. Subsequent nav­i­ga­tions skip the net­work en­tirely; the ser­vice worker an­swers di­rectly from its cache with­out even go­ing through HTTP cache. And the app keeps work­ing when the net­work does­n’t. Combined with the lo­cal-first sync en­gine (which al­ready has the user’s data in IndexedDB), Linear is us­able of­fline. You can read is­sues, cre­ate new ones, edit ti­tles and de­scrip­tions, change sta­tuses. Everything queues in the lo­cal trans­ac­tion store and flushes the next time the con­nec­tion comes back.

Modulepreload is for what the app needs now, par­al­lel-fetched so the browser never blocks on a se­r­ial im­port chain. The ser­vice worker is for what the app needs next.

So, to get load times fast the steps for Linear is to elmi­nate as much code as pos­si­ble, split it into small pieces, and pre­cache it in the back­ground. Again, the goal of all this work is to make net­work re­quests as fast as pos­si­ble or, even bet­ter, elim­i­nate them com­pletely.

Vendor bun­dle com­po­si­tion

I found it in­ter­est­ing that every pack­age Linear uses gets its own chunk, cached in­de­pen­dently. A tra­di­tional ven­dor.js in­val­i­dates the en­tire de­pen­dency graph on any bump. Linear’s chunk­ing turns ven­dor caching from a sin­gle mas­sive file to fine-grained. Bumping a sin­gle de­pen­dency in­val­i­dates one chunk; the rest stay cached.

Seems like a no-brainer and yet an­other de­tail to en­sure fast load times.

Loading mas­sive font files

Font load­ing is one of those de­tails a lot of apps get wrong. The fail­ure modes are vis­i­ble: in­vis­i­ble text for half a sec­ond, lay­out shifts as the real font swaps in, dou­ble-fetched re­sources be­cause the pre­load did­n’t match. Linear’s setup avoids all three:

<!– in <head> of in­dex.html –> <link rel=“pre­load” href=“https://​sta­tic.lin­ear.app/​fonts/​In­ter­Vari­able.woff2?v=4.1 as=“font” type=“font/​woff2” crosso­ri­gin=“anony­mous”> <link rel=“pre­con­nect” href=“https://​sta­tic.lin­ear.app crosso­ri­gin>

@font-face { font-fam­ily: Inter Variable”; font-weight: 100 900; font-dis­play: swap; src: url(https://​sta­tic.lin­ear.app/​fonts/​In­ter­Vari­able.woff2?v=4.1) for­mat(“woff2”); } /* Italic and Berkeley Mono fol­low the same shape, sin­gle woff2 each. */

Variable fonts cover the full 100 – 900 weight axis in a sin­gle woff2, elim­i­nat­ing per-weight re­quests. font-dis­play: swap ren­ders the fall­back stack im­me­di­ately and swaps to Inter when it loads. The trick that’s easy to miss: crosso­ri­gin=“anony­mous” on the pre­load tag. Without it, the browser pre­loads the font, then fetches it again when CSS later ref­er­ences it, be­cause the two re­quests have dif­fer­ent CORS modes. crosso­ri­gin on the pre­load makes the browser reuse the cached one.

This all seems sim­ple, but I’m al­ways sur­prsied at how many apps load fonts in­cor­rectly. Linear is a great ex­am­ple of think­ing through the de­tails and en­sur­ing font load­ing is as fast and ac­cu­rate as pos­si­ble.

Inlined app shell

Another key tech­nique to make the first load feel fast: Inlined in <head/> is just enough CSS to paint the load­ing state with no ex­ter­nal stylesheet fetched. Remember, the net­work is the bot­tle­neck and what you’ll al­ways be fight­ing to make your app feel fast. In this case, Linear elmi­nates a net­work re­quest by in­lin­ing the crit­i­cal CSS re­quired to show the user an app shell.

<style> :root { –bg-color: #f5f5f5; –bg-base-color: #fcfcfd; –bg-border-color: #e0e0e0; –sidebar-width: 244px; } html { back­ground: var(–bg-color); height: 100%; } body { font-fam­ily: Inter Variable”, Arial, Helvetica, sans-serif; }

#appBorders { bor­der: 1px solid var(–bg-bor­der-color); back­ground: var(–bg-base-color); mar­gin: 8px 8px 8px var(–side­bar-width); bor­der-ra­dius: 12px; }

#logo { trans­form: trans­lateZ(0); }

@keyframes lo­goB­ack­ground­Pulse { 0% { opac­ity: 0; trans­form: scale(0.8); } 70% { opac­ity: 1; } 100% { opac­ity: 0; trans­form: scale(1.0); } } </style> <script>performance.mark(“appStart”);</script>

Beyond CSS there is also a bunch of in­lined JavaScript that’s crit­i­cal to load­ing the ini­tial ex­pe­ri­ence.

<script> // Electron con­text — lets CSS branch on na­tive chrome. if (navigator.userAgent.includes(“Electron”) && nav­i­ga­tor.user­A­gent.in­cludes(“Lin­ear”)) doc­u­ment.doc­u­mentEle­ment.classList.add(“elec­tron”);

I design with Claude more than Figma now

blog.janestreet.com

For a long time I was skep­ti­cal of LLMs—whenever I reached for them I was dis­ap­pointed by the re­sults. Last year I tried Copilot and Cursor to tweak a game I’d built, and nei­ther gen­er­ated work­ing changes. At a pre­vi­ous job I tried Gemini to out­line prod­uct briefs and gen­er­ate wire­frames, but ended up throw­ing them all away. Every time I tried LLMs it was for some­thing I was al­ready good at, and they did a worse job than I would have.

Having joined Jane Street this past sum­mer, I’m find­ing AI sup­port in­dis­pens­able. There’s just so much that’s new to me, and so much I’m not good at yet, like OCaml and Bonsai. But one big sur­prise is how much it’s changed the thing I’m best at: my de­sign work­flow.

Instead of la­bor­ing over spec docs, build­ing Figma mock­ups, writ­ing pro­pos­als, and re­view­ing the im­ple­men­ta­tion with devs, I find my­self build­ing pro­to­type fea­tures that just do the ex­act thing I have in mind. What that looks like in prac­tice is:

Write some­thing de­scrib­ing the prob­lem and my pro­posal

Open my ed­i­tor, start a build, the server, and Claude, us­ing that de­scrip­tion I wrote as the prompt

Get the ba­sic func­tion­al­ity work­ing to prove to my­self that it’s pos­si­ble

Iterate on that as much as I want

Push changes to a de­vel­op­ment en­vi­ron­ment and ask users what they think

Submit a fea­ture (our ver­sion of a pull re­quest) that looks and be­haves ex­actly the way I want

A pro­to­type fea­ture in the ac­tual code­base has felt bet­ter in al­most every way com­pared to mock­ups and docs. Take a pro­to­type I made re­cently that added LLM prompt­ing to a JSQL in­put (JSQL is an in­ter­nal SQL di­alect that we use for lots of dif­fer­ent user-fac­ing tools). This pro­to­type re­ally works, and I spent days liv­ing with it and test­ing it. Claude gave me free, un­lim­ited it­er­a­tion, un­both­ered when I changed my mind for the 50th time or asked for a small tweak. I re­fined the Submit but­ton, added key­board short­cuts, tweaked copy, ad­justed the prompt, and added gen­er­ated con­fir­ma­tion mes­sages. These are work­flow im­prove­ments that would have taken days or weeks of en­gi­neer­ing and de­sign back-and-forth at my pre­vi­ous job, or more likely would just never have hap­pened.

All the ef­fort spent on this fea­ture went into im­prov­ing the real ar­ti­fact, and none on an­cil­lary in-be­tween work like cre­at­ing Figma com­po­nents or for­mat­ting docs.

It took me a while to ar­rive at this work­flow. When I joined last sum­mer, I only ap­proached smaller-sized tasks with AI, like UX pa­per­cut fixes. For big­ger ideas I was still us­ing Figma and docs, and when I tried mak­ing those things with Claude it failed.

But in the past 2 months the sit­u­a­tions where I’ve reached for Figma have fallen off a cliff. Through some com­bi­na­tion of im­proved mod­els, my own fa­cil­ity with them, and care­fully choos­ing the right scope, AI is now work­ing for big stuff too—not just the JSQL prompt but a half dozen other pro­to­types that make user-fac­ing, data model, and li­brary changes, in­clud­ing some that are 2000+ line diffs; I’m us­ing it to im­ple­ment in­ter­ac­tive pro­to­types for brand new apps af­ter de­sign­ing them in Figma; and for some new apps I’m even skip­ping Figma en­tirely, it­er­at­ing on the vi­sual de­sign from the be­gin­ning with Claude.

As a de­signer this has been em­pow­er­ing. Engineers have the abil­ity to cre­ate work­ing proofs of con­cept when they have an idea. Designers have to con­vince other peo­ple to do that for us. For an idea like direct LLM prompt­ing in the JSQL in­put” I’d be propos­ing some­thing whose fea­si­bil­ity is not even clear at the out­set; get­ting some­one to build a pro­to­type might waste their time. In other cases I might pro­pose some­thing that does­n’t clearly fill a user need. By us­ing Claude to make these ideas real I’m mak­ing it a lot eas­ier for oth­ers to eval­u­ate them—they can just use it.

But there’s a down­side: in this work­flow, the re­viewer is given a fully baked fea­ture. Does that mean they have zero in­put on the func­tion­al­ity and are just sup­posed to re­view the code? Review is not the most fun work—the equiv­a­lent in the de­sign world would be get­ting a de­tailed wire­frame from a PM and be­ing asked to make it look good. I want to make my pro­posal as clearly and com­pletely as pos­si­ble, but I still want my en­gi­neer­ing team­mates to treat it the same way they’d treat a mockup in Figma, as some­thing they and I can it­er­ate on to­gether in de­sign-space.

Our so­lu­tion for now is just to think about these fea­tures dif­fer­ently. I write a short re­minder in the de­scrip­tion: pro­to­types are liv­ing pro­posal docs, the code is dis­pos­able, and a re­view­er’s job is to give feed­back about the de­sign and user ex­pe­ri­ence. Eventually, re­view­ers still take over the idea and im­ple­ment it in a sep­a­rate fea­ture, ref­er­enc­ing the pro­to­type but own­ing the pro­duc­tion code. In prac­tice we’re still fig­ur­ing out what makes sense and feels good with this new work­flow.

There’s also a fear I have that de­sign­ing with Claude keeps me out of a fluid, cre­ative mind­set and stuck in an it­er­a­tive one, con­strained to the out­comes I think Claude can pro­duce. That’s fine for ma­ture tools, where changes are it­er­a­tive, but might mean I miss ideas when work­ing on some­thing new.

This is a fa­mil­iar ten­sion. When I was get­ting started pro­fes­sion­ally in 2011 there was a lot of dis­course about whether de­sign­ers should code. Critics ar­gued that once you’ve started pro­gram­ming you’re less likely to make big changes to an idea. But I liked mak­ing web­sites, and I liked pro­gram­ming, so I kept writ­ing code. Then, when fron­tend frame­works like React be­came com­mon and fron­tend de­vel­op­ment got more com­pli­cated, like oth­ers I de­cided to spe­cial­ize. I still made per­sonal pro­jects in React—that cer­tainly helped me in­ter­act with devs—but I spent al­most all my time at work in Figma and docs.

Had I joined Jane Street be­fore LLMs, I think I would have be­come even more en­trenched in Figma. With JavaScript I at least have some ex­pe­ri­ence; OCaml and Bonsai are en­tirely new, and con­tribut­ing on a tech­ni­cal level would have felt out of reach. Instead I’m back to mak­ing the real thing, and it feels amaz­ing to be work­ing in the medium again. I feel more free than ever to just try things.

Edwin is a de­signer on the op­tions desk at Jane Street.

Major P2P issues in Israel and possibly other middle east countries

github.com

I am not sure i am in the right place but we are all out of op­tions here since we could­n’t get any help from the game or steam sup­port.

Since around the 13/03, there is a ma­jor sys­temic prob­lem in every game that uses Steam Networking for P2P games.

For ex­am­ple, in the game Street Fighter 6, when play­ing with one Israeli or an­other with PC to PC the ping be­tween play­ers are ~120ms. when play­ing with European play­ers the ping is around 60 – 80ms which means it works well, it cur­rently af­fects only Israeli play­ers when play­ing PC to PC. Since Street Fighter 6 sup­ports cross-play we have tried play­ing PC to PS5 and the ping is a flaw­less 5 – 10ms.

It cur­rently af­fects all play­ers in Israel, we have a few dozens in our com­mu­nity with sev­eral ISPs, we have of course at­tempted speak­ing to our ISPs and port for­ward­ing and we have found no net­work is­sues on their part. in other P2P games that don’t use steam net­work­ing the is­sue is not ex­is­tent(for ex­am­ple, Tekken 8).

We are cur­rently don’t know what we can do with this is­sue since noth­ing we have done have helped and 120ms is too high for it to be playable in any P2P game.

While I can’t con­firm but heard re­ports from play­ers in other mid­dle east­ern coun­tries like Egypt that they also re­port on this is­sue so it could be re­gion-wide.

GitHub - devenjarvis/lathe: Generate hands-on, multi-part technical tutorials on demand, with LLM skills tuned to make content approachable. Then you work through them yourself, by hand ✋

github.com

An ex­per­i­ment in us­ing LLMs to teach you, rather than think for you.

Lathe gen­er­ates hands-on, multi-part tech­ni­cal tu­to­ri­als on de­mand, with skills tuned to make con­tent ap­proach­able. Then you work through them your­self, by hand, in a lo­cal UI built from the ground up for pleas­ant learn­ing. (Just like we did it in the stone age 😎)

What is it?

Generate hands-on tech­ni­cal tu­to­ri­als (single-part or a multi-part se­ries) from any prompt

Work through the tu­to­r­ial your­self in a pur­pose-built lo­cal UI

Use skills to ask ques­tions, ver­ify the tu­to­r­ial, and ex­tend it with a new part

Search, fil­ter, and man­age tu­to­ri­als from your li­brary

Every tu­to­r­ial doc­u­ments its sources, which model was used, and what prompt drove the voice” for the tu­to­r­ial

Quick start

Lathe is a com­bi­na­tion of LLM skills and a Golang CLI used to store, man­age, and view gen­er­ated tu­to­ri­als. After in­stall (below), you can gen­er­ate a tu­to­r­ial in­side any LLM ses­sion (Claude Code, Cursor, and Codex sup­ported) by prompt­ing some­thing like:

/lathe build a 3D Slicer in Erlang

Then open lathe from any ter­mi­nal:

lathe serve # starts the web server, opens the browser

Don’t worry, we also have dark mode:

Click the tu­to­r­ial you want to read and start learn­ing!

The CLI has a bunch of other com­mands, but hon­estly those were built to give the LLM a de­ter­min­is­tic way to man­age tu­to­ri­als. I ex­pect the above to be all you need (it’s all I ever use) for day-to-day. If you want to ask a ques­tion about a tu­to­r­ial, have the LLM ver­ify it, or ex­tend it with an ad­di­tional part, the UI has af­for­dances for each of these which will give you the ex­act skill/​prompt to give your LLM in or­der to trig­ger the ac­tion.

Install

Lathe is a sin­gle self-con­tained bi­nary. All you need is lathe on your $PATH; the skills run in an in­ter­ac­tive Claude Code, Cursor, or Codex ses­sion.

Homebrew (macOS, rec­om­mended):

brew in­stall de­ven­jarvis/​tap/​lathe

Distributed as a cask (a pre-built bi­nary), so it’s ma­cOS-only — on Linux use the in­stall script or go in­stall be­low.

Install script (curl | sh):

curl -sSf https://​raw.githubuser­con­tent.com/​de­ven­jarvis/​lathe/​main/​in­stall.sh | sh

Go (needs Go 1.25+):

go in­stall github.com/​de­ven­jarvis/​lathe@lat­est

From source:

git clone https://​github.com/​de­ven­jarvis/​lathe cd lathe go build -o lathe

Install the skills

The skills are bun­dled into the bi­nary. After in­stalling lathe, drop them into a pro­ject so Claude Code (or Cursor / Codex) can dis­cover them:

lathe skills in­stall # ./.claude/skills/<name>/SKILL.md (this pro­ject) lathe skills in­stall –user # ~/.claude/skills/<name>/SKILL.md (all pro­jects) lathe skills in­stall –agent cur­sor # ./.cursor/commands/<slug>.md (Cursor slash com­mands) lathe skills in­stall –agent codex # ./.agents/skills/<name>/SKILL.md (Codex Agent Skills) lathe skills in­stall –agent all # Claude Code, Cursor, and Codex lathe skills list # show the bun­dled skills

Codex uses the same SKILL.md for­mat as Claude Code, so its skills ship ver­ba­tim (and –user in­stalls to ~/.agents/skills/…). Cursor com­mands are slash-in­voked as /<slug> (e.g. /lathe); the in­ter­ac­tive hand­off model is doc­u­mented for Claude Code, so a few run­time de­tails dif­fer on Cursor and Codex.

Why does this ex­ist?

I learned how to pro­gram as a teen in the 2000s by build­ing home­brew games for my PSP (PlayStation Portable) in Lua, and then in C++. Lots of what I learned at the time was through the small PSP home­brew com­mu­nity I’m in­cred­i­bly grate­ful I got to be a part of, but I also owe much of that for­ma­tive learn­ing to free on­line re­sources and tu­to­ri­als avail­able on the in­ter­net (shoutout to 2007 cplus­plus.com - man does that site have a lot more ads now than it used to 😅). Eventually I be­came a pro­fes­sional soft­ware en­gi­neer and I spent the next decade upskilling” (though usu­ally to learn more in­ter­est­ing top­ics than needed for ) by find­ing and con­sum­ing a wealth of tech­ni­cal blogs, and more im­por­tantly for my learn­ing style - hands on tu­to­ri­als. Resources like the build-your-own-x repo, and Crafting Interpreters, and the 1,000 other one-off tu­to­ri­als that taught me every­thing from build­ing a ray­tracer, to a time­series data­base, to a lin­ear al­ge­bra ma­trix li­brary and every­thing in be­tween (seriously, I could­n’t even be­gin to list all the amaz­ing hands-on tu­to­ri­als out there that have in­flu­enced me).

Hands on learn­ing is how I’ve al­ways learned best. These tu­to­ri­als gave me the learn­ing curve I needed to go from zero-to-one in a brand new do­main, but even more im­por­tantly they gave me foot­ing and con­fi­dence to take it from one-to-two-to-ten on my own.

Fast for­ward to 2026, and now we’ve got LLMs. I’m not go­ing to go off topic about my com­pli­cated re­la­tion­ship with LLMs, but for writ­ing soft­ware they are in­ter­est­ing and in many cases they can be re­ally pro­duc­tive! But they do most of the work for you, and with that work gone they also take away the part that helped me learn a new con­cept or do­main. In some cases, that does­n’t mat­ter - we’ve got a prod­uct to ship and LLMs help us ship it faster - but for me and my joy in this field and hobby I still crave those ah ha!” mo­ments where some­thing fi­nally clicks and I have the con­fi­dence I need to be­gin shap­ing it into my own.

So lathe is an ex­per­i­ment in us­ing LLMs to teach me, rather than think for me. To recre­ate those mo­ments of hands-on learn­ing that taught me to love this work, and marry it with the po­ten­tial of a broad expert” LLM who can, in the­ory, teach me any­thing. I use lathe as a cat­a­lyst to get me started on pro­jects I would­n’t know how to start in, and can’t find any ex­ist­ing hu­man writ­ten re­sources to teach. For ex­am­ple I first came up with lathe be­cause I wanted to write a 3D Slicer Software from scratch (just find­ing doc­u­men­ta­tion on g-code was a pain, shoutout to reprap). At the time of writ­ing I’m div­ing into the world of em­bed­ded soft­ware de­vel­op­ment with Zig. Both of these cases lathe has been an ef­fec­tive tool in get­ting me from zero-to-one in ob­scure or ex­tremely young do­mains where the hu­man writ­ten re­sources just don’t ex­ist yet (and I won­der for how long hu­mans will still bother writ­ing tu­to­ri­als if only the LLMs read them…).

But what about hal­lu­ci­na­tions?

Are lathe tu­to­ri­als as good as ones writ­ten by hu­mans? Not in the slight­est. But what they lack in heart, per­son­al­ity, and ar­chi­tec­tural sound­ness, they make up for by hav­ing the tu­to­r­ial writer ready and wait­ing to an­swer all of your ques­tions, al­ways will­ing to fix or up­date their tu­to­r­ial when it is­n’t ex­actly what you wanted, and they ac­tu­ally com­plete writ­ing all 6 parts to that se­ries they started in 2018 (we’ve ALL been there 😁). Lathe is an LLM, and while I’ve built and tuned it to be as good as I know how to make it for this par­tic­u­lar task, it’s still go­ing to fail in the ways LLMs fail. I rec­om­mend us­ing the biggest thinking” model you have ac­cess to (Opus, GPT-5 Codex, etc) as these tasks are less about it­er­a­tive me­chan­i­cal ex­e­cu­tion you might op­ti­mize for when pro­gram­ming, and more about re­search­ing, de­sign­ing, and ex­plain­ing a tan­gi­ble con­cept from start to fin­ish.

Additionally, the risk for hal­lu­ci­na­tions in this con­text is, in my opin­ion, sig­nif­i­cantly lower. Lathe is built to help you do the think­ing, and is built around the ex­pec­ta­tion that you’re the one typ­ing this code out your­self. By read­ing through the guide and typ­ing it out, you are ac­tively en­gaged in the work and should be well po­si­tioned to nat­u­rally ask wait, does that make sense?” when you come across some­thing weird. At which point you can /lathe-ask (and some­times the LLM comes back with good rea­son­ing I did­n’t have be­cause it’s a for­eign do­main, and I learn some­thing) or just straight tell your LLM to up­date the tu­to­r­ial. While I have no ped­a­gog­i­cal cre­den­tials to back this up, I think I may be ac­tu­ally in­ter­nal­iz­ing con­cepts bet­ter by catch­ing and push­ing back on per­ceived slip-ups of the LLM. YMMV.

All of that said, if you can find a tu­to­r­ial writ­ten by a hu­man, I’d al­ways reach for that first. I hope more of­ten than not you do. But if you learn the same way I do and want to dive into a do­main that is light on teach­ing ma­te­ri­als, lathe is a pretty cool tool. Just re­mem­ber it is an LLM and not a hu­man. To help with this, I try to make it clear at all times what you are and are not get­ting. The lathe skills to write tu­to­ri­als will tell you when it is­n’t sure about some­thing it has writ­ten, and while I of­fer a more personal” voice, I’ve de­faulted to one that does­n’t pre­tend to be some­thing it is­n’t.

Be hon­est, did you vibecode this? Isn’t that con­tra­dic­tory to your the­sis?

Yep, lathe is vibecoded”. In this case, the scope and risk of lathe is low. It’s a liv­ing the­sis, for per­sonal learn­ing. That said, I’ve been us­ing it daily lately and it’s proven to be a use­ful and sta­ble tool in my tool­box. I’m learn­ing a lot by us­ing it, and at this point I think it’s good enough that oth­ers might ben­e­fit from it too. I ex­pect the next few point re­leases to be some in­ten­tional code/​ar­chi­tec­ture clean up to en­sure it re­mains sta­ble for oth­ers, and of course in­cor­po­rate any feed­back I get.

That said, for the sake of trans­parency, to­day I test lathe for my own use­cases - Using Claude Code on MacOS. If you are out­side of that setup, lathe should work, but I’ve not ver­i­fied it. If you’re will­ing to try it on a dif­fer­ent setup and it does work, or you end up hit­ting a bump in the road, I’d love an is­sue let­ting me know ei­ther way!

Alright then, how does it work?

LLM skills — gen­er­ate and work with tu­to­ri­als, all run in your in­ter­ac­tive LLM ses­sion: /lathe writes part-01.md, /lathe-extend adds the next part, /lathe-verify works through a tu­to­r­ial to con­firm it com­piles and runs, /lathe-ask an­swers ques­tions about a part you’re read­ing, and /lathe-tag adds search tags to ex­ist­ing tu­to­ri­als.

I moved to run­ning all of these in­ter­ac­tively, be­cause I am a Claude Code user and head­less claude -p is planned to be me­tered as of 2026 – 06-15. Maybe af­ter that change I’ll find that the cost is min­i­mal (generating tu­to­ri­als does not con­sume a lot of to­kens com­pared to vibecod­ing) and we can move some of these in­ter­ac­tions back into the UI. We’ll see!

I moved to run­ning all of these in­ter­ac­tively, be­cause I am a Claude Code user and head­less claude -p is planned to be me­tered as of 2026 – 06-15. Maybe af­ter that change I’ll find that the cost is min­i­mal (generating tu­to­ri­als does not con­sume a lot of to­kens com­pared to vibecod­ing) and we can move some of these in­ter­ac­tions back into the UI. We’ll see!

lathe CLI (Go) — copies tu­to­ri­als into ~/.lathe/tutorials/, serves the ren­dered out­put at http://​lo­cal­host:4242, and owns all durable state. It never calls an LLM it­self: the web but­tons and the lathe ver­ify/​lathe ex­tend com­mands just hand you the skill com­mand to paste into your ses­sion, and the skills call back into the CLI (lathe store, lathe ver­ify-re­sult, lathe ex­tend-start/​ex­tend-com­mit, lathe voice add) to record re­sults.

What’s up with the fancy UI?

I’m glad you asked! The lathe skills and CLI were built in tan­dem to of­fer (what I think is) a great read­ing and learn­ing ex­pe­ri­ence. A few key fea­tures that make us­ing lathe worth more than just prompt­ing Claude di­rectly (for me) are:

Full table of con­tents nav­i­ga­tion if you hover on the right side bar

Content is writ­ten with side-notes through­out to prompt me to think more deeply

Left-to-the-reader Exercises at the end of each tu­to­r­ial

Writing voices

Every tu­to­r­ial is writ­ten in a voice. A voice con­trols how the prose sounds but it does­n’t change ac­cu­racy, re­search, ci­ta­tion, ver­i­fi­ca­tion, or struc­ture, which are fixed. Two voices ship with lathe:

plain­spo­ken (the de­fault) — hon­est and pre­cise, with no in­vented per­sona or fab­ri­cated first-per­son war sto­ries. It’s writ­ten to avoid an­thro­po­mor­phiz­ing the LLM that pro­duced it.

com­pan­ion — an at­tempt at a warm, wry, first-per­son friend at the key­board”.

Pick one per run by nam­ing it in your /lathe in­vo­ca­tion (“…in the com­pan­ion voice”), or change the global de­fault:

lathe voice list # see what’s avail­able; * marks the de­fault lathe voice show com­pan­ion # print a voice’s full spec lathe voice set-de­fault com­pan­ion # change the de­fault for new tu­to­ri­als

Custom voices. If you don’t like the voices that come with lathe that’s cool, you do you. You can au­thor your own with /lathe-voice in an LLM ses­sion, and it’ll in­ter­view you about reg­is­ter, per­son, and hu­mor, draft a spec, and (on your ap­proval) save it via lathe voice add <name> –file - into ~/.lathe/voices/.

Custom voices are in­structed to not im­per­son­ate a real named per­son, fab­ri­cate cre­den­tials, or deny LLM au­thor­ship. /lathe-voice re­fuses those, and every voice is wrapped with a fixed pre­am­ble en­forc­ing the same at gen­er­a­tion time. The voice a tu­to­r­ial was writ­ten in is recorded on it (so /lathe-extend con­tin­ues in it) and is dis­closed in an au­thor­ship by­line at the top of every tu­to­r­ial: Generated by <Model> · voice <name> where the model is the spe­cific LLM used to gen­er­ate the tu­to­r­ial (e.g. Claude Opus 4.8”), and the voice name ex­pands to re­veal the full spec.

I fully rec­og­nize this is a cat and mouse game, and that any at­tempts at safety here can be cir­cum­vented. Unfortunately, whether I pub­lish lathe or not the bad ac­tors who want to flood the world with AI slop tu­to­ri­als are al­ready go­ing full steam ahead. I want to do my part though to make it clear that lathe is NOT in­tended for writ­ing con­tent out­side of your per­sonal use for your per­sonal learn­ing.

Finding tu­to­ri­als

As your li­brary grows, the web list page (lathe serve) has a search box and fil­ters to nar­row it down — all client-side, so it stays fast and of­fline:

Search matches a tu­to­ri­al’s ti­tle, topic, tags, repo, and tool ver­sions.

Sort by newest, old­est, or ti­tle (A–Z).

Filter by sta­tus, by type (single vs. se­ries), by tag, and by ver­sion.

Default port is 4242; over­ride with –port.

Storage lay­out

Tutorials live glob­ally in ~/.lathe/tutorials/, one di­rec­tory per slug:

~/.lathe/tutorials/ dig­i­tal-synth-zig/ meta­data.json part-01.md part-02.md part-03.md data­base-from-scratch-go/ meta­data.json in­dex.md

meta­data.json:

{ slug”: digital-synth-zig”, title”: Build a Digital Synth in Zig”, topic”: build a dig­i­tal synth in Zig”, created”: 2026 – 05-03T19:00:00Z”, status”: unverified”, tags”: [“zig”, audio”, dsp”], parts”: [“part-01.md”, part-02.md”, part-03.md”], tools”: [{ name”: zig”, version”: 0.13.0” }], sources”: [“https://​ziglang.org/​doc­u­men­ta­tion/​0.13.0/], voice”: plainspoken”, model”: Claude Opus 4.8″ }

Everything be­yond the core fields (slug/title/topic/created/status) is op­tional and omit­ted when empty: tools (the lan­guages/​tool­chains the tu­to­r­ial tar­gets, sur­faced as ver­sion chips and the Versions fil­ter), sources (the re­search trail — see be­low), voice and model (the by­line on the read­ing page), and repo/​re­po_branch when a tu­to­r­ial was writ­ten against a spe­cific git repos­i­tory.

Status is one of un­ver­i­fied (the de­fault af­ter lathe store; ren­ders no badge), ver­i­fy­ing, ver­i­fied, failed, skipped, or ex­tend­ing (set while /lathe-extend is writ­ing a new part). On fail­ure, a ver­ify-re­sult.json is writ­ten along­side with the failed part, step num­ber, and er­ror out­put; the web UI ren­ders it as a panel on the tu­to­r­ial page.

Sources & prove­nance

Every tu­to­r­ial keeps the re­search trail be­hind it — the URLs the gen­er­a­tion skill ac­tu­ally con­sulted while writ­ing. This is dis­tinct from the in­line ## Sources ci­ta­tions in­side a part’s mark­down: it’s a durable, tu­to­r­ial-level record stored in the sources field of meta­data.json and sur­faced in the UI as prove­nance, so you can san­ity-check where the ma­te­r­ial came from rather than tak­ing the prose on faith.

/lathe cap­tures them via lathe store –source <url> (repeatable), and /lathe-extend folds any newly-con­sulted URLs into the same trail (lathe ex­tend-com­mit –source), de-duped against what’s al­ready there.

On the list page, each card shows a · N sources count in its meta­data line.

On the read­ing page, a Researched against N sources” panel ex­pands to the full list of links.

Verification

Verification is opt-in and runs in your in­ter­ac­tive LLM ses­sion. Storing a tu­to­r­ial leaves it un­ver­i­fied and noth­ing runs un­til you ask. The lathe ver­ify <slug> com­mand, the –verify flag on lathe store, and the Verify this tu­to­r­ial but­ton in the web UI all just hand you the same com­mand to paste into your ses­sion:

/lathe-verify <slug>

The /lathe-verify skill works through every step in the tu­to­r­ial, cre­at­ing files in a fresh mk­temp -d scratch dir (never your repo), run­ning com­mands, ex­e­cut­ing each ## Checkpoint block and then calls lathe ver­ify-re­sult to record the out­come in the tu­to­ri­al’s meta­data.json. It marks the run ver­i­fy­ing when it starts and a ter­mi­nal ver­i­fied / failed / skipped when it fin­ishes.

Verification only makes sense where the tu­to­ri­al’s tool­chain is in­stalled. If a re­quired tool is miss­ing (e.g. no zig bi­nary), the run is re­ported as skipped (⚠️) rather than failed — couldn’t ver­ify here” is not the same as broken.”

Because ver­i­fi­ca­tion now runs in your own in­ter­ac­tive ses­sion, it ex­e­cutes un­der your nor­mal LLM per­mis­sion model, so you see and ap­prove the tool calls. The scratch-dir con­ven­tion keeps build ar­ti­facts out of your repo, but treat it as soft iso­la­tion at best, not a se­cu­rity bound­ary.

My Software North Star

kristoff.it

When I make soft­ware, this is my sorted list of pri­or­i­ties:

Software should be use­ful to the end user and strive to be­come soft­ware you can love.

Software should be cor­rect, as mal­func­tion­ing soft­ware de­tracts from the util­ity users can de­rive from it.

Software should be main­tain­able and ef­fi­cient, in or­der to avoid wast­ing hu­man and com­pu­ta­tional re­sources when try­ing to get more util­ity out of it.

It does­n’t mat­ter that your pro­ject has no bugs if it’s a rug­pull, or you’re oth­er­wise work­ing on user-hos­tile soft­ware.

It does­n’t mat­ter that the lan­guage you use is mem­ory-safe, if you did­n’t de­sign for cor­rect­ness or have no process that will even­tu­ally lead you to fix­ing all bugs.

It does­n’t mat­ter that your soft­ware is a beau­ti­ful canopy of ab­strac­tions, if it’s un­bear­ably slow or no­body is able to main­tain it, let alone add new fea­tures.

Sometimes I run out of steam, some­times I go down the wrong path, and some other times I de­lib­er­ately take de­tours, but no­body can trick me into mis­tak­ing lesser stars for my true des­ti­na­tion: I do care about my own de­vel­oper ex­pe­ri­ence, but only in the ex­act mea­sure that it helps me de­liver more soft­ware you can love that I and oth­ers can en­joy.

The ul­ti­mate goal is to max­i­mize util­ity for the end user; every­thing else ex­ists in ser­vice of it, and that’s my north star for mak­ing soft­ware.

To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".

10HN is also available as an iOS App

If you visit 10HN only rarely, check out the the best articles from the past week.

Visit pancik.com for more.