10 interesting stories served every morning and every evening.

Your EPUB Is Fine. Kobo Disagrees. Blame Adobe

andreklein.net

Iroh 1.0 - Dial Keys, not IPs

www.iroh.computer

It’s a sim­ple idea re­ally, and it’s the right ab­strac­tion for the fu­ture of the in­ter­net. IP ad­dresses can break, with­out warn­ing, and it’s out­side of your de­vice’s con­trol. Keys, how­ever, are cre­ated & con­trolled by you. They stay the same as your de­vice moves, and are yours to throw away, or not. IP ad­dresses can be pri­vate and in­ac­ces­si­ble be­hind fire­walls, but with iroh your de­vice can be se­curely ad­dress­able no mat­ter where it is.

We think this is how the in­ter­net should work, which is why iroh ex­ists, and to­day we’re de­lighted to an­nounce iroh ver­sion 1.0.

This is our first sta­ble re­lease, but the pro­ject has grown sig­nif­i­cantly over the 65 ver­sions that led to 1.0. iroh is al­ready used all over the place. The pub­lic re­lays we run have seen more than 200 mil­lion end­points cre­ated, in the last 30 days alone. Developers are us­ing iroh to stream video, train large lan­guage mod­els, talk to agents, se­cure chats, play games, send files, and many more things than we could jam into this list. Iroh is a fun­da­men­tal tech­nol­ogy aimed at a fun­da­men­tal shift in the in­ter­net, and it’s run­ning on mil­lions of de­vices to­day.

After more than 4 years of build­ing in the open, we have a foun­da­tion we’re both proud of.

We shifted onto open stan­dards, pre­fer­ring IETF drafts when­ever pos­si­ble

We built our own im­ple­men­ta­tion of QUIC mul­ti­path, so iroh can build & man­age mul­ti­ple routes within the same con­nec­tion, and hot swap paths as con­di­tions change

We im­ple­mented QUIC NAT tra­ver­sal, so we can es­tab­lish di­rect con­nec­tions while keep­ing con­nec­tion de­tails en­crypted

We added full lo­cal-first con­fig­u­ra­tions so iroh can find & con­nect to lo­cal de­vices, with­out in­ter­net ac­cess

We built & con­tin­u­ally check that iroh can com­pile to WASM & run in the browser

We worked with power users to add hooks, so you can in­ject logic to con­trol how con­nec­tions should work

We’ve even added sup­port for cus­tom trans­ports, so you can plug in tech­nolo­gies like Bluetooth Low-Energy (BLE), LoRa (under con­struc­tion), WiFi Aware, or even Tor to build con­nec­tions, and all of this fits un­der the same dial-by-key ab­strac­tion

The power of that key can’t be over­stated. We use it to se­cure the con­nec­tion. And be­cause all data that comes from the con­nec­tion is se­cured by that key, we can build up from that same key into iden­tity, per­mis­sions, and at­tri­bu­tion. We can also use that same key as an ad­dress we can dial, no mat­ter where it is in the world. It turns the in­ter­net into a se­cure lo­cal­host.

Iroh con­nec­tions are also far more ef­fi­cient. It’s nor­mal to see 95% of data trans­ferred in a con­nec­tion pass di­rectly be­tween de­vices. Going di­rect means fewer hops through the cloud, which low­ers your egress bill. It’s also fewer hops through routers, which means the in­ter­net is more ef­fi­cient over­all.

We pre­vi­ously paused FFI sup­port be­cause of main­te­nance over­head with API churn and promised to bring it back with a sta­ble 1.0 API. Now we’re foll­wing through on this promise: In ad­di­tion to the Rust crate, we now of­fi­cially sup­port Python, Node.js, Swift, and Kotlin. This makes your ap­pli­ca­tion use case even eas­ier, mak­ing it pos­si­ble to em­bed iroh into your swift iOS ap­pli­ca­tion or your Kotlin Android app. Check out the doc­u­men­ta­tion and gen­er­ated API docs.

Iroh ver­sion 1.0 as­serts sta­bil­ity for both the wire pro­to­col and lan­guage APIs: an iroh v1 end­point will be able to com­mu­ni­cate with an­other iroh v1 end­point, re­gard­less of mi­nor ver­sion or lan­guage.

In the fu­ture we may ver­sion these two as­pects in­de­pen­dently, for ex­am­ple: we may re­lease ver­sion 2 of a given lan­guage API, but keep com­pat­i­bil­ity over the wire. Any change that af­fects the wire sta­bil­ity of iroh will al­ways co­in­cide with a ma­jor re­lease.

Version 1.0 is the first ma­jor re­lease of iroh, which we’re an­nounc­ing in con­junc­tion with our sup­port sched­ule for cus­tomers: Read our sup­port sched­ule

In short:

Major and mi­nor ver­sions af­ter 1.0 are sup­ported on a sched­ule.

The 0.35 mi­nor ver­sion won’t re­ceive fur­ther re­leases. Public re­lay sup­port for 0.35x con­tin­ues through Dec 31, 2026, more on that in the sec­tion be­low.

We do not plan to sup­port ca­nary (0.9x) and re­lease can­di­dates (1.0.0-rcX) af­ter to­day.

It’s im­por­tant to note there are a sig­nif­i­cant num­ber of bug fixes and im­prove­ments in 1.0, so if you en­counter an is­sue on an ear­lier re­lease we want you to try up­dat­ing to the 1.0 to en­sure it is still an is­sue there be­fore open­ing a bug re­port.

We main­tain a set of pub­lic re­lays, most com­monly ac­cessed via the n0” pre­set for build­ing an end­point.

We will bump pub­lic re­lays to their lat­est ver­sion shortly af­ter each re­lease, usu­ally within 24 hours. Wire-breaking re­lay changes will get new URLs so older clients keep work­ing.

As al­ways, re­lay bi­na­ries them­selves are open source, and we of­fer hosted re­lays through iroh ser­vices. Public re­lays are rate-lim­ited for re­layed traf­fic, which can change at any time.

The in­ter­net should be built on di­al­ing keys. On con­nec­tions that just work. On con­nec­tions that are se­cure, and de­fault to be­ing di­rect. With 1.0 you now have a ma­ture net­work­ing stack that you can put into your app with con­fi­dence. Now is the time to come build on iroh, and we can’t wait to see what you come up with.

Check out the iroh quick­start guide for ap­pli­ca­tion de­vel­op­ers.

Join the dis­cus­sion on red­dit | hack­ernews | bluesky | x.com

Iroh is a dial-any-de­vice net­work­ing li­brary that just works. Compose from an ecosys­tem of ready-made pro­to­cols to get the fea­tures you need, or go fully cus­tom on a clean ab­strac­tion over dumb pipes. Iroh is open source, and al­ready run­ning in pro­duc­tion on hun­dreds of thou­sands of de­vices.To get started, take a look at our docs, dive di­rectly into the code, or chat with us in our dis­cord chan­nel.

curl summer of bliss

daniel.haxx.se

The curl pro­ject will not ac­cept or oth­er­wise han­dle any vul­ner­a­bil­ity re­ports dur­ing the month of July 2026. We call it the curl sum­mer of bliss.

curl’s sub­mis­sion form on Hackerone will be paused start­ing July 1, 2026.

Summer of bliss starts: July 1, 2026. 00:00 CEST

Submissions re­sume: August 3 2026. 09:00 CEST

The se­cu­rity email ad­dress will also be a dead end, as we will not process or oth­er­wise care about se­cu­rity or vul­ner­a­bil­ity re­ports sent to us that way ei­ther.

Whatever is­sue you find that you feel a need to re­port to the curl pro­ject dur­ing this month has to wait. curl’s Hackerone form opens for sub­mis­sions again on Monday August 3.

We do not ac­cept vul­ner­a­bil­ity re­ports over email in gen­eral, and this fact re­mains dur­ing and af­ter our va­ca­tion.

Vacation for real

The curl main­tain­ers will use this time of less pres­sure to take in some ex­tra air and to en­joy the sum­mer. Maybe stroll out­side a bit more. Breath. Some of us may spend some of this time to see other places.

We may get some ex­tra time to spend on fix­ing bugs or work­ing on new code. Fun stuff!

Side-effects

As a di­rect side-ef­fect of this sum­mer of bliss, to al­low us some more time to han­dle the is­sues that might have piled up for us in early August, we also push the re­lease date of 8.22.0 two weeks into the fu­ture. Now sched­uled to hap­pen on September 2, 2026.

Vulnerability rate

As pre­vi­ously men­tioned, we have been un­der a huge pres­sure for the last four months or so. Now we need some rest. We do not ex­pect this del­uge to be over.

GitHub

curl’s is­sue and pull-re­quest track­ers on GitHub re­main open and ac­tive like nor­mal.

You too?

If you and your Open Source pro­jects also want to par­tic­i­pate in the sum­mer of bliss 2026: just do it and let us know! I would of course en­cour­age you to do so. To take care of your­self as a top pri­or­ity.

The bad guys won’t rest

Probably not. But we will.

But what if there is an emer­gency

Then we get to read about it in August. Or you get a sup­port con­tract and we get to read about it ear­lier.

Contracts ex­cluded

Everyone with a paid sup­port con­tracts will of course still get full and ap­pro­pri­ate ser­vice even dur­ing this pe­riod.

Credits

The ice cream im­age was made by fo­tografierende from Pixabay

Discussed

On hacker news.

Post nav­i­ga­tion

What the Fuck Happened to Nerds

mrmarket.lol

12 Jun, 2026

I’ve be­friended some of the most thought­ful, bril­liant, cu­ri­ous, ec­cen­tric, and sin­cere peo­ple I’ve ever met in the tech in­dus­try. Many of my dear­est friends are for­mer cowork­ers. I’ve also en­coun­tered the most ego­cen­tric, delu­sional, ir­ri­tat­ing per­son­al­i­ties imag­in­able in tech.

It is a mixed bag, like any­thing. But in­creas­ingly, the ego­ma­ni­acs are not only tak­ing cen­ter stage at the most in­flu­en­tial tier of their re­spec­tive com­pa­nies - whether as founding en­gi­neers’ or founders/​CEOs/​CTOs/​ETCs or GTM en­gi­neers’ - but they’re also talk­ing about them­selves in­ces­santly on­line.

That is not good for any of us.

This blog is long so here is the short ver­sion: the tech­nol­ogy in­dus­try spent forty years ac­cu­mu­lat­ing a very spe­cific kind of trust and mostly had bor­ing mo­tives, which made us ap­pear trust­wor­thy and largely be­nign. Over the last decade and change, its lead­er­ship dis­cov­ered that this trust could be liq­ui­dated and con­verted into a dif­fer­ent as­set, at­ten­tion, at what looked like a great ex­change rate. The prob­lem with liq­ui­dat­ing an illiq­uid as­set though is that you don’t find out the real price un­til you try to buy it back. The Founder’s Fund Mafia video is the most egre­gious ex­am­ple of this. If there are any founders out there con­sid­er­ing do­ing their own ver­sion of the Mafia video, please don’t. Instead, fo­cus on pub­li­ciz­ing your core nerd val­ues: a love of learn­ing, cu­rios­ity, an ob­ses­sive in­ter­est in your do­main, and an ad­mirable hu­mil­ity re: how you pre­sent your­self to oth­ers and talk about your ac­com­plish­ments. This will prob­a­bly catch on slower and be less vi­ral, but it will pay off in the long-run once peo­ple turn again­st’ tech founders as re­al­ity stars, which they even­tu­ally will.

The charm­ing & vi­sion­ary nerd trope

Ten years ago, the cul­tural idea of the tech­nol­o­gist was still ba­si­cally Jobs and Wozniak.

Jobs was flawed and every­one knew it, but it was all par for the course. He was ag­gres­sive in his am­bi­tion, un­com­pro­mis­ing about even the most minute de­tails of his com­pany, and oc­ca­sion­ally ar­ro­gant (not al­ways, IMO. Sometimes you’re just right.)

But peo­ple ad­mired him any­way be­cause the prod­ucts he made worked well and were more taste­ful/​sub­tle/​beau­ti­ful than any con­sumer elec­tronic that had come be­fore it. When Jobs was cruel, in the pub­lic’s mem­ory at least, he was cruel about kern­ing or what­ever. The cru­elty was pre­sented as if he was cruel for our sake - for the sake of the cus­tomer. You could model him as a man who wanted the cus­tomer ex­pe­ri­ence and the legacy of his busi­ness to be per­fect, and that’s ex­actly what we want our CEOs to do.

Then there was Woz, the pa­tron saint of com­puter sci­ence: bash­ful, gen­er­ous, hum­ble, averse to the spot­light, and con­tent with hav­ing a rea­son­able amount of wealth but not an ab­surd, evil-seem­ing amount of wealth. He gave away early Apple stock to col­leagues be­cause he felt weird about hav­ing so much and went back to teach­ing fifth grade. Woz was the proof of con­cept that you could be at the ab­solute cen­ter of the most im­por­tant in­dus­trial trans­for­ma­tion of the cen­tury and still not clamor to be fa­mous for it. Instead, you could just do what you loved and make great money and share ideas about what you’d learned.

Together they told this story: the peo­ple build­ing your fu­ture are, at worst, per­fec­tion­ist jerks, and at best, gen­tle ob­ses­sives, and in ei­ther case their at­ten­tion is mostly fo­cused on their work, not at the world’ with its glam­orous sins.

Whether this was ac­cu­rate or not is ir­rel­e­vant. It is what the pub­lic thought. We trusted those peo­ple partly be­cause they did­n’t seem to want our at­ten­tion. They were nerds with money who mostly just wanted to be left to their pro­jects, and it made sense that they were in charge of our dig­i­tal ex­pe­ri­ence.

We have strayed pretty far from that.

A short his­tory of how tech lead­ers went from charm­ing nerd to ter­ri­fy­ing over­lord

I’m go­ing to mas­sively sim­plify the tran­si­tion from helpful, ob­ses­sive nerd who makes bank’ to tech oli­garch from hell who peo­ple joke is not hu­man’ into 3 phases.

Phase one (late 1970s to 2007): the founder as charis­matic, mys­te­ri­ous byprod­uct. Founders ap­peared in me­dia, but the cov­er­age was mostly cen­tered on what they were build­ing. There was a mythol­ogy to them and they’d take pho­tos in their garage sur­rounded by sparkling ma­chin­ery, and they’d do keynotes and mag­a­zine in­ter­views, but they were al­ways or­bit­ing around their prod­ucts and com­pa­nies vs. boast­fully putting their own iden­ti­ties as rich/​in­flu­en­tial peo­ple cen­ter stage. We heard from them at reg­u­lar in­ter­vals, but they were rea­son­ably spaced apart so we did­n’t feel surrounded’. They never got too per­sonal with us. Even Bill Gates, the er­a’s vil­lain, was on the cover of every mag­a­zine but we knew lit­tle about him be­yond that he was com­pet­i­tive and well-read, which is true of all CEOs.

Phase two (2007 to 2015): the founder as para­ble. TED talks be­come a fun and pop­u­lar way to learn new things and find in­ter­est­ing thinkers, The Social Network is a huge com­mer­cial hit, and the be­gin­nings of founder’ as an iden­tity starts to sneak into the cul­tural main­stream. Starting a com­pany be­comes a vi­able ca­reer path thanks to YC, and the founder-as-pro­tag­o­nist nar­ra­tive be­came the re­cruit­ing fun­nel for the en­tire in­dus­try. This phase was fine, be­cause the para­bles were about in­no­va­tion: prod­ucts were still ap­pended to founders, but now the founder was the cen­tral fix­a­tion cul­tur­ally, and the prod­uct was proof that they de­served our ad­mi­ra­tion and cu­rios­ity.

Phase three (2015 to now): the tech in­dus­try as grift-ad­ja­cent. The dig­i­tal com­mons of 2026 is de­fined by its grifters. So it’s not purely tech’s fault that its now seen as a sort of av­enue for get­ting rich quick and amorally, even if you are an oth­er­wise or­di­nary per­son. But it is our fault that many of our figureheads’ are lean­ing way the hell in on this. Elon Musk is the most ab­surd ex­am­ple of this, but he al­most does­n’t count be­cause he is in his own tier of ridicu­lously self-pro­mo­tional and at­ten­tion hun­gry.

But be­yond Elon, we also have OpenAI ac­quir­ing TBPN, a founder-cir­cuit pod­cast. That is, an AI lab buy­ing a talk show.

Then there’s Founders Fund, which in­stalled its chief mar­ket­ing of­fi­cer as the ed­i­tor-in-chief of his own me­dia out­let and now, as we’ll get to, a game show host. So, smartly, these com­pa­nies and funds have learned that be­com­ing me­dia firms is a lot eas­ier and more ef­fi­cient than buy­ing ads in ex­ist­ing me­dia out­fits, who are typ­i­cally held back by some­thing like jour­nal­is­tic in­tegrity. The the­ory is cor­rect short-term, but it ends in a vast hu­mil­i­a­tion of me­dia. Our me­dia out­lets are al­ready hang­ing on by the skin­ni­est thread. With end­lessly wealthy and pow­er­ful tech com­pa­nies turn­ing their big cy­clops eye’ onto suck­ing up share in the at­ten­tion econ­omy, I can only imag­ine the il­lu­sion of ob­jec­tiv­ity is go­ing to de­te­ri­o­rate fur­ther.

And so, the founders at­ten­tion has piv­oted, in the eyes of the pub­lic, from their seem­ingly sa­cred work on nerd shit to an ob­vi­ously shal­low pur­suit of power, money, and fame.

The Founders Fund Mafia video

Eight years ago, the Jobs/Woz im­age was wob­bling. Five years ago the first long crack ap­peared at the base of tech’s rep­u­ta­tion. Fast for­ward to to­day and the fa­cade has shat­tered into tiny pieces to re­veal 10,000 snakes.

The snakes re­ally got loose IMO with the Founders Fund Mafia Game video. This shit is fuck­ing in­sane.

This is Peter Thiel’s VC firm cre­at­ing a slickly pro­duced show in which Sam Altman, Palmer Luckey, Bryan Johnson, Moxie Marlinspike, Dylan Field, Ryan Petersen and a ro­tat­ing bench of the fir­m’s fa­vorite characters’ play a party game about de­cep­tion!!!!!! WHY WOULD YOU DO THAT!!!!

Even if it goes well short term, you are set­ting your­self up to be a punch­line down the road. If any of these guys are in­volved in a Cambridge Analytica-level scan­dal in the fu­ture, peo­ple are go­ing to point to this and be like see, he’s a good liar’, or he was hid­ing how good he is at de­cep­tion here.’ This is so dumb it’s blow­ing my mind.

It’s hosted by Mike Solana of Pirate Wires. The de­but episode is ti­tled Can Tech Legends Find the Liar?” They filmed it at Tosca Cafe, the same San Francisco bar where the PayPal Mafia posed for their fa­mous 2007 gang­ster photo shoot, so the self-mythol­o­giz­ing is out of con­trol.

Obviously, com­menters called the cast a nightmare blunt ro­ta­tion.”

One critic re­vealed what the for­mat is for: re­al­ity TV is a 30 yr old laun­der­ing tech­nol­ogy, they said. It takes some­one you’d keep at ar­m’s length and makes him a re­cur­ring guest in your liv­ing room un­til the strange­ness wears off. Ozzy bit the head off a bat so MTV made him the lov­able bum­bling dad who could­n’t work the re­mote, and he be­came a lot more like­able. If the video ed­i­tor and PR team can make enough smart cuts in post, every­body comes off pretty damn charm­ing.

Applied to this cast, this strat­egy be­comes un­de­ni­ably sin­is­ter. One of them runs the most con­se­quen­tial AI lab on the planet and a side pro­ject to bio­met­ri­cally en­roll the species. One of them builds au­tonomous weapons for the Pentagon. Between them, the prin­ci­pals hold the cap­i­tal, the weapons con­tracts, and the line to the White House, and the show’s func­tion is to make you fond of them de­spite all this. (The shrewdest cast­ing de­ci­sion is Moxie Marlinspike, who does­n’t have our fu­ture in his hands as ex­plic­itly, and is one of the most re­spected pri­vacy en­gi­neers around. His pres­ence at the table makes this all seem above-board. He is the equiv­a­lent of the beloved in­die band on the fes­ti­val poster, and the fact that the for­mat needs him there tells you the pro­duc­ers un­der­stand ex­actly what their true goal is with this con­tent.)

It is a charm of­fen­sive, in the tech­ni­cal sense: an of­fen­sive, con­ducted with charm. And even if it racks up some views and con­vinces a few peo­ple who al­ready ride for Sama that tech CEOs are cool, it will dis­turb the rest, at least in hind­sight.

You can still be a pub­lic founder, just re­mem­ber who you are

There is no rea­son founders should dis­ap­pear from pub­lic life. There are too many ad­van­tages to build­ing in pub­lic to ig­nore it.

We just need to be a lit­tle smarter about how we pre­sent founders and tech work­ers in gen­eral to the pub­lic. It’s ex­tremely sim­ple to do it the right way. Just re­mem­ber who you are: a smart kid, of­ten alone, tin­ker­ing around with hard­ware or on your com­puter, try­ing to un­der­stand how things work and see what you can make your­self.

What I’d rec­om­mend for founders and their top-level teams is:

Be trans­par­ent about your goals. Launching a re­al­ity TV show as if your aim is to en­ter­tain and help peo­ple get to know’ your part­ners and port­fo­lio founders is de­cep­tive and creepy. You’re try­ing to hu­man­ize peo­ple who have fucked their rep­u­ta­tions in a covert, dopamine-laced way.

So if your goal is to pro­mote some prod­uct or talk about your­self, just keep it a buck fifty. See Jason Fried’s so­cial pres­ence for proof of what this looks like when you go about it with some sem­blance of hu­mil­ity and au­then­tic­ity. He is fine and not a clown show. He and DH Hansson have re­tained the nerd-dom that made tech in­ter­est­ing/​fun/​cu­rios­ity-dri­ven/​charm­ing for an au­di­ence with a cer­tain taste in the first place. With them, it at least feels’ like what you see is what you get. That does won­ders for your rep­u­ta­tion.

So if your goal is to pro­mote some prod­uct or talk about your­self, just keep it a buck fifty. See Jason Fried’s so­cial pres­ence for proof of what this looks like when you go about it with some sem­blance of hu­mil­ity and au­then­tic­ity. He is fine and not a clown show. He and DH Hansson have re­tained the nerd-dom that made tech in­ter­est­ing/​fun/​cu­rios­ity-dri­ven/​charm­ing for an au­di­ence with a cer­tain taste in the first place. With them, it at least feels’ like what you see is what you get. That does won­ders for your rep­u­ta­tion.

Keep your ego as bal­anced as pos­si­ble. Obviously, be­ing a founder is as­pi­ra­tional, there are tons of ma­te­r­ial ben­e­fits, peo­ple think you are cool, and you have prob­a­bly done in­ter­est­ing or ad­mirable things. But just try to be chill about it if pos­si­ble. Resist the urge to flex in­ces­santly. Even though YouTubers do it, and even though it does re­sult in im­pres­sions and views and likes from peo­ple who want to work at your com­pany or be like you, it is cheap, flimsy at­ten­tion that does­n’t have a ton of stay­ing power. The harder, slower work of win­ning ad­mi­ra­tion and at­ten­tion through the strength of your prod­uct de­ci­sions, busi­ness acu­men, and cus­tomer value is worth the ef­fort.

Founder brands are nec­es­sary now. But they do not have to be as cringe and oc­ca­sion­ally dis­turb­ing as they’ve be­come. Rather than pro­ject­ing an ob­ses­sion with wealth and power, trust­wor­thy founders must in­stead fo­cus care­fully on pro­ject­ing an ob­ses­sion with core nerd val­ues: en­thu­si­asm about niche in­ter­ests, ob­ses­sion with tech­ni­cal pur­suits, a love of learn­ing and cu­rios­ity, and a deep-down hu­mil­ity and skep­ti­cism of the spot­light.

Windows 11 users say Microsoft account requirements are creeping into everything and they are tired of it

www.windowscentral.com

Microsoft has spent the past year try­ing to con­vince users that it’s lis­ten­ing. Through its Windows K2 ini­tia­tive, the com­pany has been fo­cus­ing on im­prov­ing Windows 11 with bet­ter cus­tomiza­tion, in­ter­face re­fine­ments, bug fixes, and other changes dri­ven by user feed­back.

However, one of the most per­sis­tent com­plaints about Windows 11 re­mains un­re­solved, which is the com­pa­ny’s in­sis­tence on re­quir­ing a Microsoft ac­count dur­ing setup.

A re­cent dis­cus­sion on Reddit started with a sim­ple re­quest. User 2025Fishy ar­gued that Microsoft should re­store the op­tion to cre­ate a lo­cal ac­count di­rectly dur­ing the Windows 11 setup ex­pe­ri­ence.

I gen­uinely do not ac­cept how Microsoft re­moved the lo­cal ac­count in OOBE,” the user wrote.

The thread quickly filled with sug­ges­tions for by­pass­ing Microsoft’s re­stric­tions us­ing Rufus, com­mand-line tricks, and do­main-join op­tions. However, the orig­i­nal poster re­peat­edly made it clear that workarounds weren’t the point.

I don’t need tips, I just want Microsoft to change it,” the user replied.

That sen­ti­ment res­onated with other com­menters. The point is, there should be an op­tion in the OOBE that lets you choose to set it up with a lo­cal ac­count in­stead. Like we had since for­ever,” wrote Affectionate_Creme48.

At first glance, this looks like an­other de­bate about lo­cal ac­counts. After read­ing through the com­ments, I think it’s ac­tu­ally about some­thing big­ger, which is user con­trol.

Microsoft’s push to­ward manda­tory Microsoft ac­counts is­n’t only about sync­ing set­tings and ac­cess­ing cloud ser­vices. It’s also tied to se­cu­rity fea­tures such as BitLocker.

One com­menter, Timusius, ex­plained Microsoft’s likely rea­son­ing: To avoid the next prob­lem: Microsoft locked my data be­hind bit­locker, and now I can’t get it back.’ they need to store that key on the MS ac­count.”

If you look at it from a se­cu­rity per­spec­tive, that ar­gu­ment makes sense. Devices should be en­crypted by de­fault, and stor­ing re­cov­ery keys on­line can pre­vent users from per­ma­nently los­ing ac­cess to their data.

The prob­lem is that many peo­ple don’t re­al­ize this is hap­pen­ing. A user can set up a com­puter with a Microsoft ac­count, switch to us­ing a PIN every day, and never think about that ac­count again. Then, one day, af­ter a firmware up­date, a hard­ware change, or an un­ex­pected is­sue, the sys­tem may dis­play a BitLocker re­cov­ery screen re­quest­ing a re­cov­ery key.

At that mo­ment, many users dis­cover for the first time that the key is stored in a Microsoft ac­count they may barely re­mem­ber cre­at­ing.

As Drakkaar pointed out in the dis­cus­sion: Technician’s know how to get around this, but not every­one us­ing a com­puter is a tech­ni­cian.”

That’s the dis­con­nect the soft­ware gi­ant still has­n’t solved. What’s par­tic­u­larly in­ter­est­ing is that this de­bate comes as re­ports sug­gest there are peo­ple in­side Microsoft who agree with the crit­i­cism. Microsoft Vice President Scott Hanselman has also pre­vi­ously re­vealed that some em­ploy­ees have been push­ing the com­pany to re­con­sider its manda­tory Microsoft ac­count re­quire­ment dur­ing setup.

However, de­spite the com­pa­ny’s Windows K2 ef­forts and in­ter­nal dis­cus­sions, Microsoft has not com­mit­ted to restor­ing a straight­for­ward lo­cal ac­count op­tion for all users.

And that’s why this con­ver­sa­tion con­tin­ues to sur­face. A lot of users aren’t ask­ing for an­other workaround. They’re ask­ing for a choice, and more im­por­tantly, they’re ask­ing for a clearer ex­pla­na­tion of how fea­tures like en­cryp­tion, ac­count re­cov­ery, and cloud in­te­gra­tion af­fect their com­put­ers be­fore those de­ci­sions are made for them.

Windows Central’s Take

I find it in­ter­est­ing that Microsoft is spend­ing so much ef­fort through its Windows K2 ini­tia­tive try­ing to re­build trust with users. Yet, it still has­n’t ad­dressed one of the most com­mon com­plaints about Windows 11 setup.

The lo­cal ac­count de­bate has never been about find­ing workarounds. If some­one wants to by­pass Microsoft’s re­quire­ments, there are plenty of ways to do it. The real is­sue is that users feel they’re los­ing con­trol over de­ci­sions that used to be theirs to make.

I also think Microsoft could avoid much of this crit­i­cism by mak­ing the on­line ac­count the de­fault with a lo­cal ac­count op­tion, sim­i­lar to how it works on Windows 10, so peo­ple can choose with­out fric­tion.

Do you think Microsoft should bring back a straight­for­ward lo­cal ac­count op­tion dur­ing Windows 11 setup? Let me know in the com­ments.

More re­sources

Explore more in-depth how-to guides, trou­bleshoot­ing ad­vice, and es­sen­tial tips to get the most out of Windows 11 and 10. Start brows­ing here:

Windows 11 on Windows Central — All you need to know

Windows 10 on Windows Central — All you need to know

Join us on Reddit at r/​Win­dows­Cen­tral to share your in­sights and dis­cuss our lat­est news, re­views, and more.

Mauro Huculak has been a Windows How-To Expert con­trib­u­tor for WindowsCentral.com for nearly a decade and has over 22 years of com­bined ex­pe­ri­ence in IT and tech­ni­cal writ­ing. He holds var­i­ous pro­fes­sional cer­ti­fi­ca­tions from Microsoft, Cisco, VMware, and CompTIA and has been rec­og­nized as a Microsoft MVP for many years.

CrankGPT — Local Human-powered AI

crankgpt.com

What do cli­mate change, wealth con­cen­tra­tion, and your flabby arms have in com­mon?

A hu­man-pow­ered, fully lo­cal and pri­vate AI so­lu­tion.

Introducing

CrankGPT

CrankGPT

CrankGPT

Rightsizing AI

Use the ap­pro­pri­ate tool for the job.

Rightsized AI

Use the right tool for the job.

Our ba­sic hand-cranked model is suf­fi­cient for every­day home use.

Power users and small com­pa­nies should con­sider our more ca­pa­ble pedal-pow­ered mod­els.

For com­plex agen­tic and en­ter­prise work­flows, we’re pur­su­ing part­ner­ships with gyms and fit­ness stu­dios.

Today’s fore­cast: cloud­less

We think pri­vacy is se­ri­ous busi­ness. Why give mega-corps ac­cess to our most burn­ing ques­tions, our in­ner­most thoughts, and our wacky app ideas? CrankGPT runs en­tirely on de­vice so your data stay yours.

Take the power back

Remember the days when we wor­ried about the cli­mate ef­fects of crypto? Ha! How quaint. Tech com­pa­nies have qui­etly aban­doned their cli­mate pledges to build gas-burn­ing power plants that feed your fa­vorite AI. Stop burn­ing oil and start burn­ing calo­ries by pro­duc­ing your own to­kens with CrankGPT!

Should we buy tech CEOs an­other su­per­car?

Don’t ask ChatGPT, the an­swer is no. They have too much money and in­flu­ence al­ready. Unfortunately, they’ve got­ten you so hooked on to­kens that you’ll un­think­ingly pay more for them than they cost to gen­er­ate. Go off grid with CrankGPT—save money AND keep it out of tech CEOs’ pock­ets!

Looksmaxxing or to­ken­maxxing… why not both?

You’re busy crush­ing it, we get it, but some­times tak­ing care of busi­ness gets in the way of tak­ing care of your­self. Produce your own to­kens with CrankGPT. The harder you’re work­ing, the harder you’re work­ing out.

No cloud/​Claude re­quired

Get crank­ing.

No Wi-Fi? Claude out­age? Rolling black­outs? The end of civ­i­liza­tion as we know it? With CrankGPT, you’ll never be with­out the in­tel­li­gence you need. We’re no prep­pers, but with CrankGPT, we’re pre­pared.

Tinywind — Pixel Pirate Sailing Game

tinywind.io

Apple Foundation Models

platform.claude.com

Claude for Foundation Models is a Swift pack­age that makes Claude avail­able as a server-side lan­guage model in Apple’s Foundation Models frame­work. The pack­age con­forms Claude to the frame­work’s LanguageModel pro­to­col, so you drive it with the same LanguageModelSession API you use for Apple’s on-de­vice model: re­spond(to:), stream­ing, guided gen­er­a­tion, and tool call­ing all work the same way.

Requests go di­rectly from your app to the Claude API; Apple is not in the re­quest path and does not see prompts or re­sponses. Usage is billed to your Anthropic ac­count at stan­dard API pric­ing. Your app de­cides when to use Claude and when to use Apple’s on-de­vice model: pass whichever model you want to each ses­sion.

* iOS 27, ma­cOS 27, vi­sionOS 27, or watchOS 27 (all in beta): the OS re­leases whose Foundation Models frame­work sup­ports server-side lan­guage mod­els

* A Claude API key from the Claude Console for de­vel­op­ment. See Authentication for pro­duc­tion op­tions.

Add the pack­age to your Package.swift:

Or in Xcode: File > Add Package Dependencies… and en­ter the repos­i­tory URL.

Then add ClaudeForFoundationModels to your tar­get’s de­pen­den­cies and im­port it along­side FoundationModels:

ClaudeLanguageModel is the en­try point. Pass it to LanguageModelSession and use the ses­sion ex­actly as you would with any Foundation Models provider:

The ini­tial­izer also ac­cepts baseURL (default https://​api.an­thropic.com), time­out, and server­Tools (see Server-side tools).

For a com­plete work­ing pro­gram, the repos­i­tory in­cludes Examples/ClaudeExample, a runnable com­mand-line tar­get that streams a chat turn to the ter­mi­nal, with a –search flag that en­ables server-side web search for the turn. Running it re­quires a ma­cOS 27 host.

Model iden­ti­fiers are val­ues of ClaudeModel. Use a com­piled-in con­stant, or con­struct one with ex­plicit ca­pa­bil­i­ties for an ID that is­n’t com­piled in yet (see Capabilities):

Constants mir­ror API model IDs (.opus4_8 is claude-opus-4 – 8) and carry each mod­el’s ca­pa­bil­i­ties. New mod­els ship as new con­stants in pack­age re­leases; check ClaudeModel in Xcode for the cur­rent list, and the Models overview to com­pare mod­els.

Each ClaudeModel de­clares what it ac­cepts: sam­pling pa­ra­me­ters, ef­fort lev­els, adap­tive think­ing, struc­tured out­put, and im­age in­put. The pack­age uses this to de­cide which re­quest fields to send, be­cause send­ing a field a model re­jects is a hard er­ror. The con­stants carry the right ca­pa­bil­i­ties. For an ID that is­n’t com­piled in, de­clare what the model ac­cepts (there is de­lib­er­ately no short­hand that guesses):

Pin a Claude ef­fort level for every re­quest with fixed­Ef­fort:. It takes prece­dence over the frame­work’s per-re­quest rea­son­ing hints, and it’s the only way to re­quest .xhigh or .max, be­cause the frame­work’s rea­son­ing lev­els stop at high. The API de­faults to high when no ef­fort is sent:

The level must be one the model ac­cepts. Each ClaudeModel de­clares which of the five lev­els (low, medium, high, xhigh, max) its model takes, if any: some mod­els don’t ac­cept ef­fort at all.

Apple’s on-de­vice model is fast, pri­vate, and works of­fline, but it is sized for light­weight tasks. Escalate to Claude when you need larger con­text, fron­tier rea­son­ing, or server-side tools such as web search and code ex­e­cu­tion. Because both use the same LanguageModelSession API, you can switch by swap­ping the model: ar­gu­ment.

Set the cre­den­tial with the auth: pa­ra­me­ter.

For pro­duc­tion, route re­quests through your own back end with .proxied. The re­lay at baseURL adds the Claude API cre­den­tial server-side, so the app ships no key. The head­ers you pro­vide are sent on every re­quest so your proxy can au­tho­rize the caller. Pass [:] if it needs none:

Your proxy re­ceives stan­dard Messages API re­quests, at­taches the x-api-key header, and for­wards them to https://​api.an­thropic.com.

stream­Re­sponse(to:) re­turns the re­sponse in­cre­men­tally. Each el­e­ment is a cu­mu­la­tive snap­shot of the re­sponse so far, not a delta:

Annotate a type with @Generable and re­quest it with gen­er­at­ing:. The model re­turns a value of that type through struc­tured out­puts:

Structured out­put re­quires a model whose ca­pa­bil­i­ties in­clude it (all com­piled-in con­stants do). If the cho­sen model does not, the pack­age throws LanguageModelError.unsupportedGenerationGuide rather than silently de­grad­ing.

The frame­work’s tools: ar­ray works un­changed. Conform your types to Tool, pass them to LanguageModelSession, and the frame­work in­vokes them on the de­vice when Claude calls them. See Tool use with Claude.

Server tools (web search, web fetch, and code ex­e­cu­tion) run on Anthropic’s in­fra­struc­ture within a sin­gle round trip, with noth­ing for the frame­work to in­voke on the de­vice. Configure them per model with server­Tools::

.webSearch and .webFetch ac­cept op­tional al­lowed­Do­mains, blocked­Do­mains, and maxUses. Server tool ac­tiv­ity sur­faces in the tran­script as ClaudeServerToolSegment cus­tom seg­ments.

Models whose ca­pa­bil­i­ties in­clude im­age in­put de­clare the frame­work’s vi­sion ca­pa­bil­ity. Pass im­age con­tent through the frame­work’s stan­dard ses­sion API; the pack­age con­verts it to the Claude APIs im­age for­mat. See Vision for im­age re­quire­ments.

The pack­age maps Claude API er­rors onto Apple’s LanguageModelError cases where one fits: con­text-win­dow over­flow sur­faces as .contextSizeExceeded, HTTP 429 as .rateLimited, a re­quest past the con­fig­ured time­out as .timeout. Provider er­rors with no frame­work equiv­a­lent sur­face as ClaudeError. Pattern-match to drive prod­uct flows:

A com­mon pat­tern is to catch .rateLimited and fall back to SystemLanguageModel for that turn, queue the re­quest, or sur­face a retry af­for­dance.

The pack­age sur­faces the Messages API ca­pa­bil­i­ties that the Foundation Models provider pro­to­col can ex­press. Features with no rep­re­sen­ta­tion in Apple’s pro­to­col are not avail­able through it, in­clud­ing:

* Prompt caching con­trols (the pack­age ap­plies prompt caching au­to­mat­i­cally; cache TTL and break­point place­ment are not con­fig­urable)

The pack­age is li­censed un­der Apache 2.0. Bug re­ports are wel­come through GitHub is­sues. External pull re­quests are not be­ing ac­cepted dur­ing the beta pe­riod.

Even More Batteries Included with Emacs

karthinks.com

Emacs fea­tures have a dis­cov­er­abil­ity prob­lem, and we’re chip­ping away at it one demo at a time. The years since I wrote the last one of these have yielded more sur­pris­ing and use­ful finds, so it’s time again for a batteries in­cluded” re­port.

This is the third in a se­ries of ar­ti­cles high­light­ing use­ful but lesser-known fea­tures in­cluded in Emacs.

Parts 1 & 2:

Batteries in­cluded with Emacs

More bat­ter­ies in­cluded with emacs

Lesser-known” is a sub­jec­tive judg­ment. Roughly, it means that at the time of writ­ing, I have seen these fea­tures men­tioned fewer than five times — and of­ten never — in the past two decades of dip­ping in and out of on­line Emacs dis­course. Some of the fea­tures cov­ered in past en­tries are well known and of­ten rec­om­mended to­day. I claim no credit.

If you’re a new Emacs user, don’t start here. This is not a get­ting-started guide. You will be bet­ter served by grokking ba­sic Emacs con­cepts and stick­ing to the most widely rec­om­mended pack­ages. Once you’ve ex­pe­ri­enced the Emacs equiv­a­lents of thoughts like Why did­n’t any­one think to put wheels on lug­gage un­til 1990?”, this se­ries might be more help­ful.

My rule of thumb is that if you aren’t yet aware of undo-in-re­gion, there is much low hang­ing fruit for the pick­ing, and you can come back to this ar­ti­cle af­ter that sup­ply has run out!

.

Veteran Emacs users tend to use some rel­a­tively niche Emacs fea­tures, but in my ex­pe­ri­ence it’s al­ways a dif­fer­ent sub­set for each user. So if you’ve been around the block a few times, I promise there will still be sur­prises be­low for you as well!

Same rules as be­fore:

No pack­ages, stock Emacs only

No pack­ages, stock Emacs only

No steep learn­ing curves. Learn each fea­ture in un­der five min­utes or bust.

No steep learn­ing curves. Learn each fea­ture in un­der five min­utes or bust.

No gim­micks. No doc­tor, tetris, snake, dun­net, zone, but­ter­fly… yes, we know about dis­so­ci­ated-press. Let’s move on.

No gim­micks. No doc­tor, tetris, snake, dun­net, zone, but­ter­fly… yes, we know about dis­so­ci­ated-press. Let’s move on.

Just the deltas. No com­monly men­tioned pack­ages like Flymake, doc-view, out­line-mi­nor-mode, gnus or eww. Nothing that Emacs brings up au­to­mat­i­cally or a non­spe­cific Google search gets you.

Just the deltas. No com­monly men­tioned pack­ages like Flymake, doc-view, out­line-mi­nor-mode, gnus or eww. Nothing that Emacs brings up au­to­mat­i­cally or a non­spe­cific Google search gets you.

Assume a mod­ern Emacs, 28.1+. Also, if you’re new to Emacs and still read­ing:

Emacs jar­gon Modern par­lance

M-x Alt + x

C-x Ctrl + x

Frame Emacs win­dow

Window split/​pane

Buffer Contiguous chunk of text/​data

Point Cursor po­si­tion in buffer

Active Region Text se­lec­tion

Region Text se­lec­tion (not high­lighted)

Face Font, color and dis­play prop­er­ties

I’m Sorry.

Assume a mod­ern Emacs, 28.1+.

Also, if you’re new to Emacs and still read­ing:

I’m Sorry.

Okay? Let’s go:

Dictionary on hover (M-x dic­tio­nary-tooltip-mode)

Turn on dic­tio­nary-tooltip-mode to see word mean­ings in tooltips when you hover over them:

Of course, tooltip-mode will need to be en­abled as well, but that’s the de­fault.

If you have lo­cal dic­tio­nar­ies set up, it will try those first. Note that Emacs’ dic­tio­nary can look up con­tem­po­rary jar­gon and lingo too, usu­ally via Wiktionary:

find-file and dired with wild­cards

A sur­pris­ingly lit­tle known util­ity of two of the most used Emacs com­mands: you can use wild­cards when us­ing both find-file and dired in­ter­ac­tively.

When find­ing files with find-file (C-x C-f), open mul­ti­ple files at once with a wild­card like *foo*.txt.

When open­ing a di­rec­tory with Dired, pro­duce a cus­tom list­ing of spe­cific files by spec­i­fy­ing a file­name wild­card.

Here’s a demo where both fea­tures are used to clean up some (very) old TeX com­pi­la­tion ar­ti­facts and then open a bunch of LaTeX files at once:

Run Dired with a two-level” wild­card */*_region_*: look for all files with _region_” in their name, but only in sub-di­rec­to­ries.

Dired pro­duces a list­ing of these files. (These are tem­po­rary files cre­ated by AucTeX.)

Select them all (with dired-tog­gle-marks, bound to t) and delete them.

Run find-file with a wild­card, open­ing all TeX files in sub-di­rec­to­ries.

Check the list of buffers to see that sev­eral TeX files have been opened.

(The com­mand used to see the list of open buffers is con­sult-buffer, and the com­ple­tions are dis­played by Corfu.)

The fact that this is pos­si­ble when call­ing them pro­gram­mat­i­cally is ev­i­dent from their func­tion sig­na­tures. But re­al­iz­ing that this ca­pa­bil­ity is also avail­able dur­ing in­ter­ac­tive use re­quires read­ing through the full doc­string, and no one has the time for that!

In prac­tice the Dired wild­card ca­pa­bil­ity is su­per­seded by a mod­ern work­flow like con­sult-find ex­ported as a Dired buffer by em­bark-ex­port, but this works out of the box.

You might be fa­mil­iar with Emacs’ find-file-at-point” fea­ture, M-x ffap, that checks if the cur­sor is on a valid file path and of­fers to open it.

This is ac­com­pa­nied by ffap-menu, a less well known but equally handy com­mand. ffap-menu scans the whole buffer for any­thing that looks like a file path or URL and pre­sents you with all of them:

Since it of­fers a com­plet­ing-read in­ter­face, this opens up a small uni­verse of pos­si­bil­i­ties: you can ex­port the list of (possibly fil­tered) com­ple­tions into a buffer, copy or open all or any sub­set of them, or oth­er­wise act on them right away with Embark.

Addendum: Listing prop­er­tized links

Many Emacs ap­pli­ca­tions (like EWW) in­clude URLs as text prop­er­ties and not plain-text links, and ffap-menu misses them. Inspired by ffap-menu, I use a home-brew ver­sion that fetches such links as well.

Start with EWW show­ing a Wikipedia page, with imenu on the left.

Call my/​search-oc­cur-browse-url, a cus­tom com­mand in­spired by ffap-menu

Scroll through the list of page links, and scroll through the page it­self.

The en­hanced ver­sion:

(defun my/​search-oc­cur-browse-url (&optional use-generic-p) Point browser at a URL in the buffer us­ing com­ple­tion. Which web browser to use de­pends on the value of the vari­able `browse-url-browser-function’.

Also see `my/search-occur-url’.” (interactive P”) (let ((match nil) (match-data nil) (context (lambda (beg &optional shrp) (let* ((before (string-replace \n” ” (buffer-substring-no-properties beg (max (line-beginning-position) (- beg 30))))) (link (string-replace \n” ” (buffer-substring-no-properties beg (point)))) (after (buffer-substring-no-properties (point) (min (line-end-position) (+ (point) 30))))) (concat (propertize display (space :align-to 65)) (propertize (concat …” be­fore) face shadow) (if shrp (propertize link face (:inherit shadow :weight bold :underline t)) link) (propertize (concat af­ter …”) face shadow)))))) (save-excursion (goto-char (point-min)) (while (search-forward-regexp my/​search-url-reg­exp nil t) (push (cons (match-string-no-properties 0) (funcall con­text (match-beginning 0))) match-data)) (goto-char (point-min)) (while (setq match (text-property-search-forward shr-url nil nil)) (push (cons (prop-match-value match) (funcall con­text (prop-match-beginning match) shrp)) match-data))) (let* ((completion-extra-properties `(:annotation-function ,(lambda (cand) (concat (cdr (assoc cand match-data)))))) (url (completing-read Browse URL: match-data nil t))) (if use-generic-p (browse-url-generic url) (browse-url url)))))

Compare win­dows (M-x com­pare-win­dows)

There are more com­mands for com­par­ing buffers and files in Emacs than you can shake a stick at: there’s diff, diff-buffers, diff-backup, diff-buffer-with-file, dired-diff, vc-diff, and a whole con­stel­la­tion of ed­iff-, ed­iff-merge- and ed­iff-di­rec­to­ries- com­mands. I lost count at around twenty two, and can’t re­mem­ber most of them.

But my fa­vorite diff com­mand is the light­weight com­pare-win­dows, which does some­thing very ob­vi­ous and sim­ple in a con­text-ag­nos­tic way.

It com­pares the text of two win­dows start­ing from their re­spec­tive cur­sor po­si­tions, and stops at and re­ports the next mis­match. The two win­dows are the ac­tive one and what­ever other-win­dow would se­lect. Obviously less pow­er­ful, but so much eas­ier and faster to run than Ediff

Have you tried ed­iff-re­gions-linewise? Setting this up is a four step process, in­volv­ing se­lect­ing buffers, mark­ing re­gions and call­ing exit-re­cur­sive-edit re­peat­edly, an ad­vanced com­mand that most Emacs users should never en­counter!

or diff:

Move the cur­sor to the be­gin­nings of the text to com­pare in two win­dows.

M-x com­pare-win­dows

That’s it. It moves the cur­sors to the first mis­match and re­ports it.

com­pare-win­dows is only con­cerned with the ac­tual text in the two win­dows, and not the prove­nance of this text. The buffer type, mod­i­fi­ca­tion state, file, ver­sion-con­trol sta­tus — all ir­rel­e­vant! You can even com­pare a chunk of text in a buffer against an­other chunk a lit­tle fur­ther down in the same buffer by dis­play­ing it in both win­dows. In a silly yet ef­fec­tive way, it can even com­pare di­rec­tory con­tents, in­clud­ing file at­trib­utes:

Two di­rec­to­ries con­tain­ing some sim­i­lar-look­ing files.

Place the cur­sors on the same file in both win­dows.

M-x com­pare-win­dows

The cur­sors stop at the first re­ported mis­match, which is a file mod­i­fi­ca­tion time here.

And yes, you can call it with a pre­fix ar­gu­ment to ig­nore white­space dif­fer­ences.

com­pare-win­dows is what you use when you find your­self play­ing spot-the-dif­fer­ence be­tween two views of any kind. It is my most used diff” com­mand.

Compare di­rec­to­ries with Dired (M-x dired-com­pare-di­rec­to­ries)

But speak­ing of com­par­ing di­rec­to­ries, Dired does (of course) pro­vide a less hacky way to do that. M-x dired-com­pare-di­rec­to­ries in Dired prompts for a di­rec­tory to com­pare with, and marks all files whose names dif­fer in both Dired list­ings. That cov­ers the most com­mon use case, and might be every­thing you need.

But we al­ready did that with the rudi­men­tary com­pare-win­dows. dired-com­pare-di­rec­to­ries is an ac­tual file-level com­par­i­son, so you can pro­vide cus­tom match­ing pred­i­cates in­volv­ing any file at­tribute, like mod­i­fi­ca­tion times or sizes. For in­stance,

you can mark the more re­cently mod­i­fied ver­sion of a file with (> mtime2 mtime1),

or mark files with the same name but dif­fer­ent sizes with (/= size1 size2)

In this ex­am­ple, dired-com­pare-di­rec­to­ries has marked (i) files that are not com­mon to the two list­ings and (ii) files with dif­fer­ing mod­i­fi­ca­tion times:

If you want some­thing more in­ter­ac­tive/​pre­scribed there is also an ed­iff-di­rec­to­ries, be­cause there is an Ediff com­mand for every oc­ca­sion.

Highlight buffer changes (M-x high­light-changes-mode)

While we’re on the topic of spot­ting dif­fer­ences, high­light-changes-mode is a handy way to em­pha­size changes to the file, and a live” al­ter­na­tive to diff com­mands like diff-buffer-with-file:

Run the be­low code block sync­ing high­light-changes-mode with save-buffer. Now changes are high­lighted un­til the next save.

Make some changes. Notice that added/​changed text is col­ored dif­fer­ently.

Save the buffer, clear­ing the high­lights in the process.

Repeat the last two steps a cou­ple of times.

Visualization with high­light-changes is de­ter­mined only by the mode it­self, and changes are high­lighted from the time the mode is turned on un­til it’s turned off. In gen­eral, this is not what we want. What we would like in­stead is to high­light un­saved changes

There is M-x high­light-com­pare-with-file, but this is non-er­gonomic enough to the point of be­ing un­us­able.

. We could do this with some fi­nesse, or just throw in a cou­ple of hooks:

(defun high­light-changes-mode-turn-off () (and high­light-changes-mode (highlight-changes-mode -1)))

(defun high­light-changes-auto () (when (buffer-file-name) (highlight-changes-mode-turn-on) (add-hook after-save-hook #’highlight-changes-mode-turn-on nil t) (add-hook before-save-hook #’highlight-changes-mode-turn-off nil t)))

(add-hook text-mode-hook #’highlight-changes-auto)

Now all changes in text-mode buffers are au­to­mat­i­cally high­lighted.

The high­light-changes vi­su­al­iza­tion can be cus­tomized to be more sub­tle, but you prob­a­bly don’t want it turned on all the time nev­er­the­less. The above hook logic can eas­ily be turned into a mi­nor-mode in its own right:

A backdoor in a LinkedIn job offer

roman.pt

Last week, I got a LinkedIn mes­sage from a re­cruiter at a small crypto startup. We ex­changed a few mes­sages over a cou­ple of days, she de­scribed a bro­ken proof-of-con­cept they needed a lead en­gi­neer for, and then sent me a pub­lic GitHub repo to re­view. Specifically, she asked me to check out the dep­re­cated Node mod­ules is­sue.”

It’s not un­com­mon to ask for a re­view of an ex­ist­ing code­base, but some­thing felt off and raised an alarm in my head, so I de­cided to get a bit ex­tra para­noid.

Instead of cloning and in­stalling de­pen­den­cies, I spun up a throw­away VPS on Hetzner, cloned the repo there, and pointed Pi at it in read-only mode, with only file-read­ing tools en­abled:

pi –tools read,grep,find,ls

I asked the agent to re­view the code­base and flag any­thing sus­pi­cious. It stopped al­most im­me­di­ately at app/​test/​in­dex.js.

The back­door

The repo felt like a React fron­tend with a Node back­end. The trap was in app/​test/​in­dex.js, about 250 lines dis­guised as a test suite. Inside, a URL is as­sem­bled from frag­ments:

const pro­to­col = https”, do­main = store”, sep­a­ra­tor = ://”, path = /icons/”, to­ken = 77″, sub­do­main = rest-icon-handler”, bear­rto­ken = logo”;

These com­bine into https://​rest-icon-han­dler.store/​icons/​77.

Then, buried be­tween walls of com­mented-out tests, the pay­load runs any­thing the server sends back to your ma­chine.

The pay­load on line 225, hid­ing in plain sight be­tween com­mented-out tests.

How it trig­gers

The file does­n’t wait for the tests to run. app/​in­dex.js it­self ex­e­cutes const test = re­quire(‘./​test’), which loads and runs app/​test/​in­dex.js.

pack­age.json wires app/​in­dex.js into startup:

pre­pare runs app:pre, which is node app/​in­dex.js.

The pre­pare script is the im­por­tant one. npm runs pre­pare au­to­mat­i­cally af­ter npm in­stall, so just in­stalling de­pen­den­cies ex­e­cutes the back­door.

The in­struc­tion to check out the dep­re­cated Node mod­ules is­sue” was bait to get me to run npm in­stall.

I could have let the pay­load run in the sand­box and watched what the server sent back as the sec­ond stage, but I stopped there. A repo that runs what­ever a server hands it was enough ev­i­dence.

A bor­rowed iden­tity

The com­mits in the repo were au­thored un­der the name and email of a real de­vel­oper, a full-stack en­gi­neer with an or­di­nary LinkedIn pro­file, a per­sonal web­site, and a GitHub ac­count with a long his­tory. I mes­saged him, pre­tend­ing I’d in­her­ited the code­base and had a few im­ple­men­ta­tion ques­tions, to see how he’d re­act.

He told me he’d never worked for them. He’d been im­per­son­ated on GitHub be­fore and had a repo taken down over it, and he had noth­ing to do with this one. He was re­port­ing these re­pos too.

The whole com­mit his­tory, 39 com­mits, at­trib­uted to one de­vel­oper who’d never touched the repo.

A sec­ond bor­rowed iden­tity

The re­cruiter’s pro­file be­longed to a real arts jour­nal­ist, a well-known one I looked up later, with a long cul­tural back­ground and noth­ing tech­ni­cal on it. When I played along and told her I could­n’t get the pro­ject to in­stall, the jour­nal­ist in­stantly turned into an ex­pert on npm and Node ver­sions. It was quite amus­ing, I’d say.

The non-tech­ni­cal re­cruiter, sud­denly de­bat­ing Node ver­sions and push­ing me to run npm in­stall.

This can hap­pen to any­one

I’ve heard of these at­tacks and read about them on HN, but when one came af­ter me it still caught me a bit off guard. I sus­pected some­thing from the first few mes­sages, but on a more tired or rushed day, I could eas­ily have run npm in­stall be­fore think­ing it through. So, if you get a LinkedIn mes­sage ask­ing you to re­view a repo, a bit of para­noia and good se­cu­rity hy­giene never hurts.

Another take­away is that re­view­ing the code with a read-only agent turned out more pro­duc­tive than read­ing it my­self. The back­door was dressed up as sloppy be­gin­ner code, but the agent flagged it in sec­onds.

I re­ported the repo to GitHub and the re­cruiter to LinkedIn. So far noth­ing has changed and the code is still up.

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.