10 interesting stories served every morning and every evening.

Zig Creator Calls Spade a Spade, Anthropic Blows Smoke

raymyers.org

I ha­rass the sea with my tiny boat and am called a pi­rate, you do it with a great fleet and are called a king.

I ha­rass the sea with my tiny boat and am called a pi­rate, you do it with a great fleet and are called a king.

Anthropic is ac­tively cam­paign­ing to end soft­ware en­gi­neer­ing. They need you to be­lieve they can do that. Well, maybe it’s not you that they need to con­vince. Maybe it’s your C-Suite, var­i­ous world lead­ers, or the man­ager of your re­tire­ment fund. They’ve raised $132 bil­lion in in­vest­ment, and are ap­proach­ing an IPO val­ued over $1 tril­lion. Since they can­not show prof­itabil­ity, this de­pends on sell­ing their hy­po­thet­i­cal fu­ture im­pact.

In lit­er­ary terms, Anthropic is an un­re­li­able nar­ra­tor.

One of their key nar­ra­tives is: Coding is go­ing away, then the rest of soft­ware en­gi­neer­ing, and even­tu­ally most other hu­man la­bor. This kind of money be­hind this kind of story has an im­pact, re­gard­less of how true we think the story is.

People will make ar­chi­tec­ture, prod­uct, and staffing de­ci­sions based on these events. Many of those de­ci­sions will be based on fear - fear of lay­offs, rap­ture-esk warn­ings of be­ing Left Behind”, Doom Trolling, etc…

To make good de­ci­sions we need to think clearly, which is hard right now. Put on your skep­ti­cal hat.

Views are my own. I have no his­tory with Zig. I’ve never spo­ken to Andrew Kelley, but found his re­cent JetBrains in­ter­view a great watch.

My in­ter­est here is in pub­lic lit­er­acy about AI in soft­ware. That’s been my ca­reer fo­cus now for 3 years, along with im­prov­ing the tech­nol­ogy it­self. During half of that time I was Chief Architect of a cod­ing agent startup - both a cus­tomer of Anthropic’s mod­els and com­peti­tor to their agent Claude Code. My cur­rent pro­ject is The Coding Agency.

So where were we?

This week, Anthropic / Bun put out their ex­pla­na­tion of the de­ci­sion to port Bun from Zig to Rust. This ex­pla­na­tion came two months af­ter merg­ing the mi­gra­tion to the main­line. Explaining the di­rec­tion be­fore­hand would have been more tra­di­tional in an in­fra­struc­ture pro­ject like this, but mean­while the de­lay con­ve­niently al­lowed the story to be car­ried by sexy head­lines like The Register’s Anthropic’s Bun Rust rewrite merged at speed of AI. Much in­vest. Very wow.

Zig’s cre­ator Andrew Kelley has now put out a re­sponse with his own thoughts. It’s blunt, to an un­usual de­gree. That has ques­tion­able op­tics. As a gen­eral rule, you would not want to worry that when you switch pro­gram­ming lan­guages you will wake up the next morn­ing to the old lan­guage’s leader un­load­ing on your per­sonal flaws. As Dax hi­lar­i­ously put it:

guys we have a pretty sub­stan­tial open­source zig code­base and i’m ter­ri­fied he’s gonna look at it

guys we have a pretty sub­stan­tial open­source zig code­base and i’m ter­ri­fied he’s gonna look at it

Still, as I read Andrew’s piece I found my­self cheer­ing out loud. I may have briefly jumped around the room. Some called his take a meltdown”, all I can say is he’s gained a new fan to­day.

Sometimes things need to be called out.

What is model be­hav­ior?

On my best days I’d as­pire to some­thing like Buddhist right speech, a high stan­dard that every­thing we say should meet all five of these cri­te­ria.

Is it true?

Is it help­ful?

Is it timely?

Is it kind?

Is it from kind­ness?

We’re break­ing deco­rum a lit­tle, stray­ing into true, but un­kind” ter­ri­tory. I’m de­fend­ing some­one’s choice to do that. I don’t do that lightly, and I hope it’s help­ful.

Background

Just to catch you up…

Bun is a TypeScript run­time, like a faster NodeJS.

Zig is a sys­tems pro­gram­ming lan­guage, like a mod­ern C.

Bun was writ­ten in Zig un­til re­cently - one of the largest Zig code­bases.

Bun claims near 100% AI con­tri­bu­tions.

Zig al­lows 0% AI con­tri­bu­tions.

Bun was ac­quired by Anthropic, a lead­ing AI model lab.

Bun’s founder ex­per­i­mented with a mas­sive agen­tic rewrite from Zig to un­safe Rust.

That ex­per­i­ment was merged days later and is now the of­fi­cial ver­sion.

This is sit­u­a­tion is con­tro­ver­sial on a few fronts, though ap­par­ently no one in­volved ac­tu­ally wants Bun to stay in Zig. The drama lives purely in the meta-dis­cus­sion. The mi­gra­tion process it­self is pretty in­ter­est­ing, I would con­sider do­ing some­thing sim­i­lar in the right sit­u­a­tion.

Who to be­lieve

When peo­ple choose be­tween Zig and Rust for their pro­jects, they will nat­u­rally see the Bun sit­u­a­tion as a data-point. That fact that one of the biggest Zig users wound up re­vers­ing the de­ci­sion feels rel­e­vant, re­gard­less of the rea­sons. People will try to un­der­stand what hap­pened, and de­cide which is more true:

Anthropic/Bun story: Bun tried every­thing rea­son­able, and was still over­whelmed by mem­ory bugs be­cause Zig was­n’t up to the task.

Anthropic/Bun story: Bun tried every­thing rea­son­able, and was still over­whelmed by mem­ory bugs be­cause Zig was­n’t up to the task.

Andrew’s story: The Bun code is a mess be­cause of their en­gi­neer­ing de­ci­sions, in­clud­ing overus­ing AI agents to write and re­view every­thing.

Andrew’s story: The Bun code is a mess be­cause of their en­gi­neer­ing de­ci­sions, in­clud­ing overus­ing AI agents to write and re­view every­thing.

I’d lean more to­ward the lat­ter, but I sus­pect the dom­i­nant fac­tor is more bor­ing:

Ray’s story: Faced with a le­git­i­mate chal­lenge of mem­ory bugs, there were sev­eral vi­able op­tions. Management ea­gerly ap­proved the Rust rewrite op­tion be­cause it was a great mar­ket­ing op­por­tu­nity to show­case their new Fable model, Anthropic al­ready uses Rust, and Zig is openly against us­ing Anthropic’s prod­ucts.

Ray’s story: Faced with a le­git­i­mate chal­lenge of mem­ory bugs, there were sev­eral vi­able op­tions. Management ea­gerly ap­proved the Rust rewrite op­tion be­cause it was a great mar­ket­ing op­por­tu­nity to show­case their new Fable model, Anthropic al­ready uses Rust, and Zig is openly against us­ing Anthropic’s prod­ucts.

That makes fine busi­ness sense, it just is­n’t a mar­ket­ing story. The mar­ket­ing needed to fo­cus on how their AI was pow­er­ful enough to do this rewrite (even though it was not pow­er­ful enough to catch a use-af­ter-free).

For bet­ter or worse, this bag­gage is now top-of-mind in the Rust vs Zig ques­tion. The sit­u­a­tion tends to pit Jarred’s judge­ment against Andrew’s in the eye’s of the com­mu­nity. Any face-sav­ing ex­ag­ger­a­tion spo­ken through Anthropic’s mega­phone could un­in­ten­tion­ally af­fect Zig’s rep­u­ta­tion.

I can un­der­stand why rather than leave well enough alone, Andrew would de­cide to… add some con­text.

Is this a smear?

From my per­spec­tive, Anthropic is the party we need to hold ac­count­able here. That’s what this is all about. Bun founder Jarred Sumner is get­ting caught in the cross­fire in a sense. So is Zig.

It would be nice if this could be dis­cussed strictly on the tech­ni­cal points, and we’ll get to them. However, I don’t think Anthropic is mak­ing a tech­ni­cal ar­gu­ment, they are deal­ing in spec­ta­cle.

Anthropic is us­ing Jarred’s cred­i­bil­ity to help sell their nar­ra­tive. In re­spond­ing to that, we’re com­ment­ing on his cred­i­bil­ity. That’s messy. I don’t love it.

Still, if re­port­ing the things that some­one says and does comes off as a smear, then maybe that be­hav­ior was part of the prob­lem too.

The meat grinder

My first im­pres­sion of the Bun pro­ject was the 2022 an­nounce­ment, in­clud­ing this warn­ing to re­cruits.

Oven is go­ing to be a grind, es­pe­cially the first nine months or so. If work-life bal­ance means a lot of time spent not work­ing, it’s prob­a­bly not a good fit.

Oven is go­ing to be a grind, es­pe­cially the first nine months or so. If work-life bal­ance means a lot of time spent not work­ing, it’s prob­a­bly not a good fit.

When I see a state­ment like that from a prospec­tive man­ager, it says a num­ber of things, not the least of which is this per­son has no idea what they are do­ing”. A lot of rea­son­ably good coders have never seen an ex­am­ple of a good man­ager, and have all kinds of weird ideas about what man­age­ment is.

Running at crunch time” all the time is bad for health and bad for pro­duc­tiv­ity. That is a ro­bustly es­tab­lished fact about knowl­edge work. For some ref­er­ences, see the Human Factors sec­tion of Hillel’s Empirical Software Engineering.

My ad­vice? Don’t work for peo­ple that brag about 90 hour weeks. Work for peo­ple who will de­fend your abil­ity to sleep at night.

In Andrew’s piece, he sum­ma­rizes what he’s heard from the grapevine of the Bun team’s ex­pe­ri­ence:

Poor com­mu­ni­ca­tion, un­re­al­is­tic ex­pec­ta­tions, low em­pa­thy, no ex­pe­ri­ence. Just a to­tal shit show

Poor com­mu­ni­ca­tion, un­re­al­is­tic ex­pec­ta­tions, low em­pa­thy, no ex­pe­ri­ence. Just a to­tal shit show

I mean… of course it was. The hearsay is es­sen­tially re­peat­ing what was an­nounced pub­licly. Their job list­ing might as well have said, now seek­ing ap­pli­cants for to­tal shit show”. It’s bad form for us to say this out loud. We’re sup­posed to let the Tech Bros go on about how cut­ting cor­ners is some ge­nius pro­duc­tiv­ity hack. Then the peo­ple that lis­ten to them can even­tu­ally call us in to fix the re­sults. It would be a great arrange­ment if I cared less about out­comes. It’s quite lu­cra­tive.

FWIW, I’ve used Bun a few times and liked it well enough. Cool tech is of­ten pro­duced in spite of bad work en­vi­ron­ments. I’m not the one say­ing that their en­vi­ron­ment re­sulted in a buggy un­main­tain­able mess, Bun is the one say­ing that.

Say some­thing nice

The piece about the mi­gra­tion process is very cool, with de­tails that are reusable. No com­plaints, I think that’s the real con­tri­bu­tion here. I par­tic­u­larly like the hon­esty in ex­plain­ing that this was a port to un­safe Rust, al­low­ing a lit­eral file-by-file mi­gra­tion to min­i­mize risk, paving the way for re­design in fu­ture steps. That’s a sen­si­ble move ex­plained well.

There’s some truth to the idea that lan­guage choice is be­com­ing more re­versible. This method will take it’s place among other types of rewrite au­toma­tion with pros and cons. These tech­niques can be com­bined and fur­ther hard­ened with Formal Methods. Darpa’s TRACTOR (Translating All C to Rust) re­search pro­gram pub­lished a re­port this year which should cover the state of the art.

My fa­vorite book on soft­ware mod­ern­iza­tion pro­jects is Kill It With Fire by Marianne Bellotti. As agents al­low us more moves we can make with old code, we still need good judge­ment and com­mu­ni­ca­tion in de­cid­ing where to go. Let’s talk about that next.

The rewrite ra­tio­nale is fluff

These are the ba­sic in­gre­di­ents of ex­plain­ing a tech­ni­cal de­ci­sion:

What is the mo­ti­va­tion?

What op­tions did you con­sider?

What are the pros and cons?

Here’s a great ex­am­ple by Richard Feldman on his de­ci­sion to move the Roc com­piler from Rust to Zig. I was ini­tially shocked by that move (I’m some­what fa­nat­i­cal about lan­guage safety), but ul­ti­mately his points made sense and this started my cu­rios­ity about Zig.

When the Bun rewrite was merged, I’d hoped to see a sim­i­lar treat­ment. This is what we got in­stead, two months late.

✅ What is the mo­ti­va­tion?

⚠️ What op­tions did you con­sider?

🚫 What are the pros and cons?

For the as­pir­ing tech leads out there: When you skimp on these in­gre­di­ents, es­pe­cially the pros and cons”, you risk giv­ing the im­pres­sion that you ap­proached the prob­lem with one an­swer al­ready in mind and are giv­ing it a post-hoc jus­ti­fi­ca­tion. Maybe you have rea­sons that you aren’t say­ing.

It feels dis­hon­est.

All pros no cons

Rather than a real trade­off com­par­i­son, we get a Bun is bet­ter in Rust” sec­tion cov­er­ing only up­sides. A change like this al­ways has trade-offs, an ob­vi­ous one would be build time.

Typically when you use Rust for a large code­base, you are buy­ing safety and pay­ing in slower com­pi­la­tion. There’s no shame in that, it can be a win­ning bar­gain. In that past, this fac­tor was im­por­tant enough to Bun that they forked the Zig com­piler to try and im­prove it. If we’re right that the Rust port in­creased build time for con­trib­u­tors, why not dis­close that? It comes off as more cred­i­ble to own the im­pact and the pri­or­i­ties that make it right move over­all.

They also seem to be padding the list by mix­ing in other im­prove­ments they’ve made af­ter the rewrite that aren’t re­ally re­lated to it.

They did­n’t try a style guide?

Recall that the mo­ti­va­tion was mem­ory bugs. Definitely not Bun’s only source of bugs but a fre­quent one, caus­ing four fix com­mits per week by my count. Painful.

Theoretically, every mem­ory bug rep­re­sents a vi­o­la­tion of some con­ven­tion - an ex­pec­ta­tion of how this kind of ob­ject should be dealt with. Therefore it be­hooves us to es­tab­lish a clear idea of what’s ex­pected in what cir­cum­stance. We should try to use any lan­guage ef­fec­tively for that mat­ter, Rust style guides are a thing too, but man­ual mem­ory man­age­ment adds scope to the ex­pec­ta­tions we need.

How have other peo­ple solved this prob­lem? Another flag­ship Zig code­base is TigerBeetle, a fi­nan­cial trans­ac­tion data­base. It is not plagued by mem­ory bugs, in fact it ap­pears to be one of the most re­li­able data­bases in ex­is­tence. They will gladly tell you that this is due to their TigerStyle ap­proach and some in­no­v­a­tive test­ing strate­gies. Worth a look! The word style” might un­der­sell it, it’s a whole en­gi­neer­ing phi­los­o­phy with Zig cod­ing guide­lines as one el­e­ment.

Here’s a taste of TigerStyle. Not every ap­pli­ca­tion can copy-and-paste this ex­act strat­egy, but it il­lus­trates the re­la­tion­ship be­tween mem­ory al­lo­ca­tion and other de­sign de­ci­sions.

All mem­ory must be sta­t­i­cally al­lo­cated at startup. No mem­ory may be dy­nam­i­cally al­lo­cated (or freed and re­al­lo­cated) af­ter ini­tial­iza­tion. This avoids un­pre­dictable be­hav­ior that can sig­nif­i­cantly af­fect per­for­mance, and avoids use-af­ter-free. As a sec­ond-or­der ef­fect, it is our ex­pe­ri­ence that this also makes for more ef­fi­cient, sim­pler de­signs that are more per­for­mant and eas­ier to main­tain and rea­son about, com­pared to de­signs that do not con­sider all pos­si­ble mem­ory us­age pat­terns up­front as part of the de­sign.

All mem­ory must be sta­t­i­cally al­lo­cated at startup. No mem­ory may be dy­nam­i­cally al­lo­cated (or freed and re­al­lo­cated) af­ter ini­tial­iza­tion. This avoids un­pre­dictable be­hav­ior that can sig­nif­i­cantly af­fect per­for­mance, and avoids use-af­ter-free. As a sec­ond-or­der ef­fect, it is our ex­pe­ri­ence that this also makes for more ef­fi­cient, sim­pler de­signs that are more per­for­mant and eas­ier to main­tain and rea­son about, com­pared to de­signs that do not con­sider all pos­si­ble mem­ory us­age pat­terns up­front as part of the de­sign.

Clearly, if we’re weigh­ing a rewrite in Rust, we’d first con­sider if we should use the cur­rent lan­guage dif­fer­ently. Hear’s how Bun’s write-up pre­sents that op­tion.

Many pro­jects opt to an­swer these kinds of ques­tions through a style guide. TigerBeetle’s TigerStyle is an ex­am­ple in Zig and Google’s 31,000 word C++ style guide is an­other. The chal­lenge with style guides is en­force­ment. How do you make sure the style guide is fol­lowed? Historically, code re­view was the an­swer with best-ef­fort en­force­ment via lin­ters & sta­tic an­a­lyz­ers.

Many pro­jects opt to an­swer these kinds of ques­tions through a style guide. TigerBeetle’s TigerStyle is an ex­am­ple in Zig and Google’s 31,000 word C++ style guide is an­other. The chal­lenge with style guides is en­force­ment. How do you make sure the style guide is fol­lowed? Historically, code re­view was the an­swer with best-ef­fort en­force­ment via lin­ters & sta­tic an­a­lyz­ers.

I ex­pected the next sen­tence to dis­cuss Bun’s style guide, why it was­n’t work­ing, per­haps how it evolved over time… nope. They seem to just pay lip-ser­vice the pri­mary way the com­mu­nity ad­dresses their prob­lem, shrug their shoul­ders and move on. Did I miss some­thing? Over four years on a pro­ject of this size, it’s sur­pris­ing they did­n’t se­ri­ously at­tempt this if they ex­pe­ri­enced these prob­lems. It’s al­most like the pro­ject was run by some­one who tries to hold all the con­text in their head and never have meet­ings.

What’s more be­wil­der­ing is that they dis­miss style guides with hes­i­ta­tions that are re­futed within their own ar­ti­cle. Consider that clas­sic ob­jec­tion that guides are hard to en­force. Fair, though maybe an odd bar­rier for a team ad­vanced enough to fork the com­piler they use. Here’s the thing, they al­ready claim to have solved the en­force­ment prob­lem be­cause they use agen­tic re­view. PORTING.md is it­self a style guide, scoped to the mi­gra­tion process. They have just con­ducted an agen­tic re­view of their en­tire rewrit­ten code­base against strin­gent guide­lines and de­clared it a suc­cess.

This does­n’t make sense. Let’s as­sume agen­tic re­view works, I think it can un­der the right cir­cum­stances. That would re­quire de­sign and well-thought guide­lines. I think they were sim­ply more ex­cited about putting that men­tal en­ergy into a rewrite than a re-ar­chi­tec­ture, for any num­ber of un­stated rea­sons. It may have been the right choice.

We’re still wor­ried about syn­tax?

There’s one more bit I want to nit­pick, a com­mon cog­ni­tive dis­so­nance in dis­cus­sions about agent-first cod­ing. Bun’s piece briefly dives into to the weeds of what a style guide op­tion” might look like.

Having a rigid style guide with clear own­er­ship ex­pec­ta­tions ex­plic­itly spelled out in the type sys­tem was a real op­tion for Bun. Since Zig has no op­er­a­tor over­load­ing, we would likely end up with a lot of code look­ing some­thing like this:

Claude Code Is Way More Token-Hungry Than OpenCode. We Measured Exactly How Much

systima.ai

We put Claude Code and OpenCode on the same model, the same ma­chine, and the same tasks, then ex­am­ined every­thing sent and re­ceived.

Be the first to know when we pub­lish orig­i­nal re­search or thought pieces on AI and quan­tum gov­er­nance. NOTE: To reach out, please Book a call” in­stead.

No spam. Unsubscribe at any time.

Claude Code is far hun­grier:

When we asked both har­nesses for a one-line re­ply, Claude Code used roughly 33,000 to­kens of sys­tem prompt, tool schemas, and in­jected scaf­fold­ing be­fore the prompt even ar­rived. OpenCode used about 7,000.

Claude Code is far more cache in­ef­fi­cient:

OpenCode’s re­quest pre­fix was byte-iden­ti­cal in every run we cap­tured; it paid to cache its pay­load once per ses­sion and read it back for pen­nies.

Claude Code on the other hand re-wrote tens of thou­sands of prompt-cache to­kens mid-ses­sion, run af­ter run, and on the same task wrote up to 54x more cache to­kens than OpenCode.

Cache writes of course are billed at a pre­mium, which ac­counted for the us­age dash­board climb­ing when us­ing Claude Code.

Config fur­ther bloats the prompt:

A pro­duc­tion repos­i­to­ry’s 72KB in­struc­tion (AGENTS.md or CLAUDE.md) file adds an­other (avg) 20,000 to­kens to every sin­gle re­quest. Five mod­est MCP servers add 5,000 to 7,000 more. By the time a real work­ing setup sends its first re­quest, it is 75,000 to 85,000 to­kens deep be­fore the user has typed a word.

Subagents add to the cost:

A small task that cost 121,000 to­kens done di­rectly cost 513,000 to­kens when fanned out to two sub­agents. This is be­cause each sub­agent is its own agent that re-reads its own sys­tem prompt and tools on every turn it takes, so a fan-out mul­ti­plies the num­ber of full base­lines in flight.

Having said that, the par­ent in­gests only each sub­agen­t’s re­turned re­sult, not its whole tran­script.

We found one re­sult in favour of Claude Code:

On a multi-step task Claude Code’s whole-task to­tal came out lower than OpenCode’s, be­cause it batches tool calls into fewer re­quests while OpenCode re-pays its smaller base­line turn af­ter turn. The me­ter starts higher; how the ses­sion un­folds de­cides who spends more. That ad­van­tage held on the first model we tested; re-run on a newer one, the same task took twice the re­quests and cost roughly 298,000 to­kens against OpenCode’s 133,000.

Every find­ing above was cross-checked on a sec­ond model fam­ily. The pat­tern held, with one nu­ance we cover be­low.

The rest of this post shows how we mea­sured all of this at the API bound­ary, where the to­kens go, and what prompt caching does and does not save you.

Why mea­sure this at all

Every to­ken of har­ness pay­load is a to­ken of work­ing con­text you can­not spend on your task.

If you op­er­ate agen­tic AI in pro­duc­tion, par­tic­u­larly un­der the EU AI Act where Article 12 ex­pects you to log and un­der­stand your sys­tem’s be­hav­iour, what does my agent ac­tu­ally send” is a ques­tion you should be able to an­swer with data.

Method

We spliced a log­ging proxy be­tween each har­ness and the model end­point.

har­ness (Claude Code / OpenCode) → log­ging proxy (captures re­quest pay­loads + re­sponse us­age) → model end­point

The proxy records two things per re­quest. The first is the ex­act JSON pay­load the har­ness emit­ted, mean­ing the sys­tem blocks, tool schemas, and mes­sages. The sec­ond is the us­age block the API re­turned, cov­er­ing in­put to­kens, cache writes, cache reads, and out­put to­kens.

The pay­load cap­ture is ground truth for what the har­ness sends. The us­age block is ground truth for what was me­tered.

We tested un­der these con­di­tions.

Harnesses. Claude Code 2.1.207 and OpenCode 1.17.18, both pinned to claude-son­net-4 – 5, July 2026. A re­duced ma­trix (the floor, the cache task, and the multi-step task) was later re-run pinned to claude-fa­ble-5; where the model changed the re­sult, we say so in­line.

Baseline iso­la­tion. Fresh con­fig di­rec­to­ries with no MCP servers, no user set­tings, and no mem­ory; an empty work­space with no in­struc­tion files; per­mis­sions by­passed. Multiplier lanes then add one vari­able at a time.

Tasks. T1 says Reply with ex­actly: OK and iso­lates fixed over­head (three runs per har­ness). T2 reads a seeded file and sum­marises it. T3 is a write-run-test-fix loop against FizzBuzz plus a checker script.

Quality check. A sep­a­rate ten-lane bench­mark, five runs per har­ness against a seeded, hash-ver­i­fied test suite, scored pass rates along­side to­ken cost; re­ported in the qual­ity sec­tion.

Zero-tools vari­ant. Claude Code with –tools ” and OpenCode with tools”: {“*”: false}, sep­a­rat­ing sys­tem prompt from tool schema weight.

One full dis­clo­sure note be­fore the num­bers:

Our traf­fic passes through Meridian, a lo­cal gate­way that bridges the Claude Code SDK to a stan­dard Anthropic end­point so a Claude Max sub­scrip­tion can drive third-party tools. It wraps every re­quest in the SDKs own en­ve­lope, a con­stant we mea­sured at roughly 6,200 to­kens on the Sonnet path and 3,500 on the Fable path with bare cal­i­bra­tion re­quests and sub­tracted from every me­tered fig­ure be­low.

Payload-level fig­ures come from the cap­tured re­quest bod­ies, which the gate­way can­not af­fect, and are ex­act.

Character-to-token con­ver­sion for com­po­nent es­ti­mates uses each har­ness’s own mea­sured ra­tio of 4.1 to 4.4 char­ac­ters per to­ken, de­rived from cold-cache an­chors where the me­tered write equals the full pay­load, rather than a generic heuris­tic.

Part I. The floor

The fixed over­head of say­ing OK

The task was 22 char­ac­ters. Here is what each har­ness sent with it on its first re­quest.

Component

Claude Code

OpenCode

System prompt

27,344 chars, 3 blocks

9,324 chars, 1 block

Tool schemas

27 tools, 99,778 chars

10 tools, 20,856 chars

First-message scaf­fold­ing

7,997 chars of <system-reminder> blocks

none

The ac­tual prompt

22 chars

22 chars

First-turn pay­load (calibrated)

~32,800 to­kens

~6,900 to­kens

OpenCode’s re­quest is close to min­i­mal. There is one sys­tem block that opens with You are OpenCode, the best cod­ing agent on the planet”, plus ten clas­sic cod­ing tools, plus the user’s prompt as the only con­tent.

Claude Code’s re­quest is a plat­form boot­strap. The 27 tools in­clude the cod­ing core plus an en­tire back­ground-agent and or­ches­tra­tion suite, from CronCreate and Monitor to the Task fam­ily, work­tree man­age­ment, and push no­ti­fi­ca­tions.

Before the user-en­tered prompt, its first mes­sage car­ries three in­jected re­minder blocks; a cat­a­logue of agent types for del­e­ga­tion, a cat­a­logue of avail­able skills, and user con­text.

Tool schemas are the dom­i­nant term for both. Roughly 24,000 of Claude Code’s ~33,000 to­kens are tool de­f­i­n­i­tions, ver­sus roughly 4,800 of OpenCode’s ~6,900.

Zero tools, pure har­ness

Stripping the tools iso­lates the sys­tem prompt it­self. Claude Code’s weighs in at 26,891 chars, about 6.5k to­kens. OpenCode’s is 8,811 chars, about 2.0k to­kens.

Both har­nesses trim their prompt slightly when tools are dis­abled. Even with no tools at all, Claude Code’s in­struc­tion set is over three times the size of OpenCode’s; the resid­ual is be­hav­ioural doc­trine, mean­ing tone rules, safety guid­ance, task-man­age­ment in­struc­tions, and en­vi­ron­ment de­scrip­tion.

A one-tool task

T2 asked each har­ness to read a file and sum­marise it. Both pro­duced cor­rect sum­maries.

Claude Code took 6 HTTP re­quests and roughly 199,000 cu­mu­la­tive me­tered in­put to­kens. OpenCode took 4 re­quests and roughly 41,000, plus one Haiku side call for ses­sion ti­tling.

Most of those to­kens are cache reads billed at a tenth of the in­put price. Three things scale with pay­load re­gard­less; the first-turn cache write, the per-turn read, and con­text-win­dow con­sump­tion, which no cache dis­count re­duces.

A 33k-token base­line means every turn starts a sixth of the way into a 200k win­dow be­fore any code en­ters the con­ver­sa­tion.

A multi-step task, where the gap closes

T3, the write-run-test-fix loop, in­verted the ex­pec­ta­tion set by the base­lines.

Metric

Claude Code

OpenCode

Model re­quests

3

9 (+1 ti­tle call)

Tool-calling style

par­al­lel batch in one round trip

one tool call per turn

Cumulative me­tered in­put

~121,000 to­kens

~132,000 to­kens

Claude Code batched the en­tire job, two file writes and two script ex­e­cu­tions, into a sin­gle par­al­lel tool round trip. OpenCode made ex­actly one tool call per turn and took nine.

Because the base­line is re-sent on every re­quest, re­quest count mul­ti­plies base­line. OpenCode paid its ~7k base­line nine times, Claude Code paid its ~33k three times, and the to­tals con­verged.

Whole-task in­put roughly equals base­line times re­quest count, plus con­ver­sa­tion growth. A large-base­line har­ness that batches ag­gres­sively and a small-base­line har­ness that se­ri­alises can land in the same place.

Two struc­tural de­tails emerged from the pay­loads:

Claude Code in­jects an ad­di­tional <system-reminder> block as the con­ver­sa­tion pro­gresses, three on the first turn and four by the first tool round trip, so its scaf­fold­ing grows with turn count.

OpenCode’s per-turn mar­ginal pay­load, roughly 400 to 2,200 chars per turn, is pure con­ver­sa­tion con­tent.

Does a newer model change the pic­ture?

We re-ran the floor on Claude Fable 5 to check whether the gap was a Sonnet arte­fact, and it shrank (which we did­n’t ex­pect).

Claude Code’s sys­tem prompt is model-con­di­tional. It sent 27,787 chars of in­struc­tions to Sonnet but only 10,526 to Fable, with tool schemas also trimmed from 99,778 to 82,283 chars. Same 27 tools, much less doc­trine.

OpenCode’s pay­load was byte-iden­ti­cal across both mod­els.

The floor gap on Fable comes out at roughly 3.3x by pay­load against 4.7x on Sonnet. Still far hun­grier, but the ra­tio is model-de­pen­dent.

The multi-step con­ver­gence did not sur­vive the change ei­ther:

On Fable, Claude Code took six re­quests in­stead of three, in­clud­ing an 85,686-token mid-ses­sion cache re-write, and landed at roughly 298,000 to­kens against OpenCode’s 133,000.

Therefore the batch­ing ad­van­tage is model be­hav­iour, not a har­ness con­stant.

These lanes also pro­duced OpenCode’s only mid-ses­sion cache write in the en­tire study, a sin­gle event of roughly 6,000 to­kens; every­thing else it sent stayed byte-sta­ble.

One served-model note be­longs here:

Under Fable we re­ceived re­sponses al­ter­nately as claude-fa­ble-5 and claude-opus-4 – 8, con­sis­tent with those tiers shar­ing in­fra­struc­ture.

How to read more books

scotto.me

I’ve read roughly a book a week for a few years, and I can tell you it’s doable. I did­n’t al­ways read this much. When I started, I read fewer than ten vol­umes per year, but mak­ing it a goal made me switch gears and achieve what I once thought was im­pos­si­ble. I want to ex­plain to you here what I did to be­come a pro­lific reader, and what I learned in the process, so that, with a bit of ef­fort, you can do it too. I promise, it will be worth it.

First of all, you don’t have to make time to read. What you need to do is read every sin­gle time you are not do­ing some­thing else. In to­day’s world, most peo­ple pick up their phones as soon as they get a mo­ment of in­ac­tiv­ity. Serious read­ers pick up their books in­stead. So an ef­fec­tive way is to re­place the time you spend in front of a screen, like PCs, smart­phones, and TVs, with read­ing a book.

This is prob­a­bly the most dif­fi­cult part. I had to re­move all so­cial me­dia and stream­ing apps from my iPhone. I re­moved Instagram, YouTube, Facebook, etc. When I started, I found my­self pick­ing up the phone and im­me­di­ately notic­ing that some­thing was miss­ing, since the only things left to do were check the weather, read bor­ing emails, or see my bank ac­count. After a few days my brain started remap­ping it­self, and I felt less pres­sure to im­me­di­ately reach for my phone as soon as I had noth­ing to do. I also wear a cheap ana­log watch so I can check the time on my wrist and I don’t have to reach for my phone.

Once you block your smart­phone, you might find your­self a bit un­com­fort­able with hav­ing noth­ing to oc­cupy your mind for ten min­utes. This is the per­fect time to boost your read­ing habit. You need to make sure you al­ways have a book with you every­where you go. I usu­ally read a few pages as soon as I wake up, and the same be­fore falling asleep. I read a book when I cook lunch or din­ner, and I read a book when eat­ing break­fast. I love us­ing pub­lic trans­port, es­pe­cially trains, be­cause I get time to read when some­one else is dri­ving for me.1 I al­ways have a book with me when I go out with my part­ner, even if I don’t usu­ally end up read­ing it. If she has to run an er­rand and I have to wait, I don’t waste my free time with noth­ing to read. I have be­come good at walk­ing my dog while read­ing — I even got com­pli­mented for that by a stranger — and I make sure I never go to the bath­room with­out a book.”

I love the smell of book ink in the morn­ing.” — Umberto Eco

I love the smell of book ink in the morn­ing.” — Umberto Eco

Having a book wher­ever I go can be­come prob­lem­atic, de­pend­ing on the size of it. The best so­lu­tion I have found is to use an ebook reader. They are thin de­vices that can fit in a pocket and are able to carry hun­dreds of books in mem­ory. I think that for a reader, it might be one of the best in­ven­tions ever, con­sid­er­ing how ex­pen­sive books were through­out his­tory and also how dif­fi­cult it is to carry them. An ebook reader can solve those prob­lems; more­over, you can have a back­light for read­ing in the dark — it works dif­fer­ently from an LED screen and does­n’t strain the eyes — and you can also high­light text and get de­f­i­n­i­tions for words. However, it’s not re­ally a re­place­ment for a book. Reading only us­ing an ebook reader af­ter a while feels like read­ing the same book, even if the story changes. I like to al­ter­nate dig­i­tal books and phys­i­cal ones, and I al­ways pre­fer pa­per­backs since they are eas­ier to carry around and cheaper to buy.

I also tend to read mul­ti­ple books at the same time. Sometimes it hap­pens that I get so into a book that I put the rest on pause be­cause the story is grab­bing all my at­ten­tion, but in gen­eral I like to have a few books that I read in par­al­lel. Having only a sin­gle op­tion can be­come bor­ing. I gen­er­ally mix fic­tion and non-fic­tion to have a broader choice.

What to read is an hard ques­tion. I’ve read some­where a phrase that puts it quite well: read what you like un­til you like to read.” My sug­ges­tion is to read broadly, chang­ing gen­res and sub­jects, be­cause there are nicely writ­ten books in every genre, and be­cause it teaches you dif­fer­ent per­spec­tives. Before or af­ter, you will un­der­stand which gen­res you re­late to more.

It is fool­ish to think that you have to read all the books you buy, as it is fool­ish to crit­i­cize those who buy more books than they will ever be able to read. It would be like say­ing that you should use all the cut­lery or glasses or screw­drivers or drill bits you bought be­fore buy­ing new ones.” — Umberto Eco

It is fool­ish to think that you have to read all the books you buy, as it is fool­ish to crit­i­cize those who buy more books than they will ever be able to read. It would be like say­ing that you should use all the cut­lery or glasses or screw­drivers or drill bits you bought be­fore buy­ing new ones.” — Umberto Eco

Another se­cret is to not be scared of quit­ting a book. I def­i­nitely start way more than I fin­ish. But I don’t con­sider an un­com­pleted book a fail­ure or a bad book. I think that some­times books have a cer­tain time to be fully ap­pre­ci­ated. So if I don’t fin­ish a book to­day, I might try read­ing it again in the fu­ture. I still re­mem­ber hav­ing aban­doned Siddhartha by Herman Hesse at least three times at the first few pages, be­fore read­ing it en­tirely and con­sid­er­ing it one of the most for­ma­tive books of my life. Somehow I was­n’t ready for it, and I had to wait to be­come ca­pa­ble of fully un­der­stand­ing it. Also, I be­lieve there are way more bad books out there than good books. If you feel that you are not lik­ing one, it feels bor­ing and makes you think you are wast­ing your time, just close it and move on. I have closed books by au­thors that I loved be­cause they weren’t good — in that mo­ment.

If you are a se­ri­ous reader, you need a li­brary, and to make your own li­brary you need phys­i­cal books. So try to get books that in­ter­est you and put them on the shelves for later. When I buy new books, it is mostly be­cause I need a spe­cific one I can­not find oth­er­wise, or be­cause I want to sup­port lo­cal in­de­pen­dent book­shops. However, I get more used books than new ones. I usu­ally find them in the book sec­tion of used stores, at mar­kets, book fairs, and some­times in the book boxes that I find around the city.2

An ef­fec­tive method to push your­self to read more is to set some goals. You can pick a rea­son­able num­ber of books for the month or the year and try to reach it. Progress track­ing is one of the known tricks used to form new habits. Goodreads, for ex­am­ple, has what’s called the Reading Challenge to help you keep track of what you read in a year, and I found it mo­ti­vat­ing to put in the ef­fort to main­tain the num­ber I wanted to read. However, count­ing the vol­umes is not a healthy way of read­ing. It’s much bet­ter to read great books and take the right amount of time to un­der­stand and re­flect on them rather than rush­ing to fin­ish to in­crease the fi­nal count. You need to en­joy the process and get a good out­come from your read­ing.

Writing a re­view is also a great method to make a book stick in your mem­ory. Taking high­lights and notes while you’re read­ing is a good thing, but re­vis­it­ing them along­side your thoughts in a writ­ten doc­u­ment is some­thing dif­fer­ent. Reviewing books is a great way to be­come bet­ter at un­der­stand­ing what the mes­sages con­tained in the books are and what the key el­e­ments of the story are. In ad­di­tion, if you like writ­ing, it’s a good pre­text to prac­tice.

One of the du­ties of a se­ri­ous reader is to find what to read next. I al­ways have a long list of books to read, but I don’t stick to it all the time. I like to be im­mersed in some­thing new and dis­cover new au­thors or gen­res. What I usu­ally use are two things: Goodreads and YouTube. The first one is great for read­ing com­ments and un­der­stand­ing if a book is what we think it is and what peo­ple we fol­low (make sure to fol­low good read­ers) think about a book. So Goodreads helps me form an idea of a book be­fore I get to read­ing it. YouTube, on the other hand, is great for get­ting rec­om­men­da­tions and lis­ten­ing to spoiler-free re­views to get some ideas. There are many great chan­nels out there, and I watch quite a few of them. One of my favourites in English is Better Than Food, which has re­viewed great books for more than a decade.

What in­spired me to try to read more was this video, where Max Joseph ex­plains that be­com­ing a se­r­ial reader is just a mat­ter of mak­ing a daily habit of read­ing a few pages, with sur­pris­ingly good re­sults. Also, Ryan Holiday — a fa­mous au­thor — has re­cently pub­lished a good guide on how to read more books with his own tips and tricks.

Last rec­om­men­da­tion: avoid hacks. Avoid speed read­ing. And don’t try to force your­self to in­crease your read­ing speed. It will come nat­u­rally the more you read. Avoid sum­maries and sum­mary ser­vices. It might be okay to use them af­ter you read a book to make sure you did­n’t miss some parts, but read­ing a sum­mary does not equal read­ing a book. Avoid even au­dio­books. Big cor­po­ra­tions want to grab your at­ten­tion by try­ing to mar­ket au­dio­books as books for busy peo­ple, but don’t fall for the trap. A book is just bor­ing black text on a white page be­cause that’s how it’s meant to be con­sumed, and it re­quires your en­tire at­ten­tion. Listening to au­dio while cook­ing or clean­ing or what­ever you do is not the same thing; you are not 100% con­cen­trated on the con­tent. Also, read­ing is faster than lis­ten­ing, so use your time wisely.

Footnotes

I con­sider dri­ving a huge waste of time. Sometimes it can be fun and ad­ven­tur­ous, but I think life is too pre­cious to drive to work every day. ↩︎

I con­sider dri­ving a huge waste of time. Sometimes it can be fun and ad­ven­tur­ous, but I think life is too pre­cious to drive to work every day. ↩︎

In Australia, some peo­ple put a wooden box with a door filled with books in their front yards, so that every­one pass­ing by can pick one up or put their own into it for the next read­ers. ↩︎

In Australia, some peo­ple put a wooden box with a door filled with books in their front yards, so that every­one pass­ing by can pick one up or put their own into it for the next read­ers. ↩︎

I love LLMs, I hate hype

geohot.github.io

I think from this blog you may mis­un­der­es­ti­mate how ab­solutely giddy I am about AI. I did hack­ing from 2007 – 2014, af­ter that my whole ca­reer has been de­voted to AI. I love the progress. I’m so ex­cited for the new LLMs, self dri­ving cars, video gen­er­a­tion mod­els, and cod­ing agents. I set up a Linux box with open­code on my lo­cal GLM-5.2 last week and wow like just say­ing in­stall tmux with the geo­hot con­fig­u­ra­tion works; the Year of the Linux Desktop is fi­nally here!

What I don’t like is two things. One, this con­stant bull­shit about some win­dow clos­ing, or the per­pet­ual un­der­class, or falling hope­lessly be­hind. This is neg­a­tive va­lence hype, not only is it not true, it’s mostly de­signed to make you feel bad about your­self and move to shitty San Francisco where every­thing re­ally does suck like how these peo­ple claim.

And two, this straw­man jump from, oh hey, it’s a fancy au­to­com­plete, smart com­piler, bet­ter search en­gine, to it’s gonna like own the whole light cone bro like if you aren’t in SF and at the right par­ties there’s gonna be like a flash of light in the sky one day and you’re not even gonna know what hap­pened but every­thing just Changed. I’ll bet you every­thing I have that this does­n’t hap­pen. The peo­ple per­pet­u­at­ing this are ter­ri­ble peo­ple, but the jus­tice is that this is how they feel in­side all the time them­selves.

Here’s a cool pre­sen­ta­tion from 2016 about su­per­in­tel­li­gence. Here’s a movie from 1991 about ma­chines tak­ing over the world. A cer­tain cult likes to claim credit for things that are hap­pen­ing with or with­out them, and this is my main ar­gu­ment against the val­u­a­tion of fron­tier labs. It’s not that AI won’t cre­ate that much value, it’s that they won’t cap­ture it.

They try to dress it up with some high minded safety or China bull­shit, but the core of the anti open source ar­gu­ments is a fear of com­mod­i­fi­ca­tion. AI is some­thing that’s hap­pen­ing mostly due to Moore’s law and gen­eral progress in com­put­ing, not some­thing that they are do­ing. Of course they have a strong in­cen­tive against you find­ing this out, be­cause then you might not want to give them bil­lions of dol­lars.

I might have been a lit­tle harsh in The Eternal Sloptember about mod­els not be­ing able to pro­gram. What’s re­ally hap­pen­ing is that pro­gram­ming is chang­ing. Can com­pil­ers pro­gram? Here’s a Linus Torvalds quote about how agents make pro­gram­ming 10x more pro­duc­tive, but com­pil­ers make pro­gram­ming 1000x more pro­duc­tive. I think 10x and 1000x are ex­treme es­ti­mates, but I’m now pretty con­fi­dent I’m get­ting bet­ter at us­ing them and get some boost from the mod­els. It is a new skill, and it’s not like I haven’t con­stantly been try­ing them. You have to be re­ally care­ful, they can in­crease cog­ni­tive fa­tigue, and all the vibe coded stuff is still slop (where’s all this new mag­i­cal soft­ware that the pro­duc­tiv­ity im­prove­ments should im­ply?). But mod­els are use­ful just like find re­place, stack over­flow, or all the regexes I never learned how to write and now never will!

AI is the con­tin­u­a­tion of the com­puter rev­o­lu­tion. I love com­put­ers so much.

Your Browser Does Math Differently on Every OS, and Anti-Bot Systems Read the Bits

scrapfly.dev

Fingerprinting is usu­ally about can­vas, WebGL, fonts, au­dio. There is a qui­eter sig­nal, and it lives in the last bits of a num­ber.

Run this in any con­sole:

Math.tanh(0.8) // 0.6640367702678491 gen­uine Linux Chrome (glibc) // 0.664036770267849 gen­uine ma­cOS Chrome (libsystem_m) // 0.6640367702678489 gen­uine Windows Chrome (UCRT)

That out­put is an ap­prox­i­ma­tion, and its ex­act bits de­pend on the OS that com­puted it. A gen­uine Mac runs Math.tanh through Apple’s math li­brary. Linux runs it through glibc1. The two dis­agree on about a quar­ter of all in­puts, usu­ally by one unit in the last place (1 ULP2). Windows, through the Universal C Runtime, dis­agrees with both on a few per­cent, and on the in­put above all three land on a dif­fer­ent bit.

The same call, run on gen­uine Chrome 150 across three real ma­chines:

Measured over the DevTools pro­to­col on Chrome 150: Linux (glibc), ma­cOS 26 on Apple Silicon (libsystem_m), Windows 11 (ucrtbase.dll). tanh(0.5) is one of the roughly three-in-four in­puts where every­one agrees, which is ex­actly why it makes a use­less probe. tanh(0.8) is one that sep­a­rates all three at once.

One tanh call on the right in­put is a per-OS sig­na­ture. Claim ma­cOS, re­turn Linux math bits, and you have con­tra­dicted your own User-Agent.

This tell is re­cent. Until Chrome 148, V8 com­puted tanh it­self with a bun­dled fdlibm3 port, so it re­turned the same bits on every OS and leaked noth­ing. V8 com­mit c1486295ae5 re­placed it with std::tanh, which reads the host libm. It first shipped in V8 14.8.57, which is Chrome 148. Chrome 147 and ear­lier do not leak here. Chrome 148, 149, and 150 do.

Scrapfly ships a browser that has to match a real one across hun­dreds of sig­nals, and math is one of the harder ones.

Why one func­tion re­turns dif­fer­ent bits

IEEE 7544 de­fines how a dou­ble is stored. It does not re­quire sin, cos, tanh, or exp to be cor­rectly rounded. Correct round­ing is ex­pen­sive, so every ven­dor ships a libm5 that trades a frac­tion of a ULP for speed, with its own min­i­max6 co­ef­fi­cients, lookup ta­bles, and re­duc­tion con­stants.

The three im­ple­men­ta­tions pro­duce three sets of bits:

Linux: glibc

ma­cOS: Apple lib­sys­tem_m

Windows: UCRT7 (ucrtbase.dll)

They agree al­most every­where and split just of­ten enough to clas­sify the OS. A de­tec­tor needs no math, only a table: gen­uine ma­cOS Chrome re­turns one pat­tern for cos(1), gen­uine Linux Chrome re­turns an­other, and a sin­gle com­par­i­son tells them apart.

Four traps

Just reim­ple­ment the Mac func­tions” breaks on con­tact, for four rea­sons.

1. Only some math leaks. V88 ships its own math and links it sta­t­i­cally: Math.exp, Math.pow, Math.atan, and most of the rest come from bun­dled llvm-libc9, and Math.sin / Math.cos from a bun­dled glibc-de­rived dbl-64 rou­tine. All of them are iden­ti­cal on every OS, so spoof­ing them cre­ates an in­con­sis­tency. The ex­cep­tion is Math.tanh: since Chrome 148 V8 com­putes it with the plat­form std::tanh in­stead of the bun­dled rou­tine it used be­fore, so it now reads the host libm. It is the only Math.* that leaks the OS, and that asym­me­try is it­self check­able.

2. JavaScript math and CSS math are dif­fer­ent code paths. CSS sin(), cos(), and atan2() do not share code with Math.sin. The lay­out en­gine re­duces the an­gle in de­grees, then calls plat­form std::sin on the re­duced value. That gives a dif­fer­ent re­sult than a di­rect ra­dian sin(), and it hits the host libm, so all seven CSS trig func­tions leak. We re­pro­duced the de­gree re­duc­tion and the ra­di­ans-to-de­grees step bit-for-bit, not just the leaf func­tion.

3. ma­cOS has two math li­braries that dis­agree. Apple Silicon car­ries scalar lib­sys­tem_m and the Accelerate frame­work10’s vec­tor rou­tines (vvsin, vvtanh). They are dif­fer­ent code. Across a mil­lion in­puts they di­verge on 10 to 89 per­cent, de­pend­ing on the func­tion. Take cos(0): scalar re­turns ex­actly 1.0, Accelerate re­turns 0.9999999999999999. So reproduce Apple’s math” is un­de­fined un­til you know which li­brary the browser calls, at which site. We re­solved it by dri­ving real Chrome on a real Mac over the de­bug­ging pro­to­col and read­ing the ex­act dou­ble. Answer: scalar lib­sys­tem_m backs Math.tanh, CSS trig, and the au­dio com­pres­sor’s per-sam­ple tran­scen­den­tals. Accelerate backs Chrome’s Web Audio DSP on Mac, the FFT, the vec­tor math, and the bi­quad fil­ters (fft_frame_mac.cc, vec­tor_­math­_­mac.h, bi­quad.cc, all BUILDFLAG(IS_MAC)). Pick the wrong li­brary for a given call site and you land 1 ULP off on most in­puts, worse than not spoof­ing.

4. Architecture leaks. ARM and x86 dif­fer on fused-mul­ti­ply-add and on NaN sign prop­a­ga­tion. A re­pro­duc­tion that is cor­rect on pa­per drifts if the com­piler fuses a mul­ti­ply-add on one tar­get and not the other.

The map: what leaks where

Put the rout­ing on one page. Bold is the host libm (glibc, Apple lib­sys­tem_m, or UCRT), the code that leaks the OS. Everything else is iden­ti­cal on every ma­chine and safe to leave alone.

V8 bun­dled = sta­t­i­cally linked and iden­ti­cal on every OS: llvm-libc for most func­tions, a glibc-de­rived dbl-64 rou­tine for sin/​cos. host libm = the plat­form li­brary that leaks the OS (libsystem_m on Mac, glibc on Linux, UCRT on Windows). Accelerate = Apple’s vDSP, which Chrome uses for the Mac Web Audio DSP.

V8 routes al­most every­thing through its own bun­dled math, so JavaScript Math is a tell in ex­actly one place, Math.tanh. CSS is a tell every­where, be­cause Blink calls the host libm di­rectly for every trig func­tion. Web Audio on Mac runs on Accelerate for the FFT and the vec­tor stages, while the DynamicsCompressor’s per-sam­ple tran­scen­den­tals stay scalar lib­sys­tem_m, so one au­dio graph touches three sep­a­rate li­braries.

WASM is not in the table be­cause it has no tran­scen­den­tal op­codes. sin and friends come from what­ever libm the mod­ule bun­dled, and its arith­metic (f64.sqrt, f64.mul) is hard­ware, so WASM math is iden­ti­cal on every OS. Its only fin­ger­print axis is the ARM-versus-x86 split in NaN canon­i­cal­iza­tion and a few SIMD round­ings.

The tells clus­ter in three sur­faces: Math.tanh, every CSS trig func­tion, and Web Audio, where the Accelerate FFT car­ries the CPU ar­chi­tec­ture and the com­pres­sor’s scalar lib­sys­tem_m car­ries the OS.

How to close it

No noise. Perturbing the out­put fails twice. A ref­er­ence com­par­i­son sees a value that matches no real OS, and per-call ran­dom­ness breaks de­ter­min­ism, which is its own tell. The tar­get is a value iden­ti­cal to the OS you claim, which noise can­not pro­duce.

Reproduce the al­go­rithm ex­actly. Recover the tar­get’s min­i­max co­ef­fi­cients, ex­po­nent ta­bles, and re­duc­tion con­stants from its libm, and tran­scribe them to portable C. Match every bit, in­clud­ing the in­puts where the tar­get rounds the wrong way. Here is Apple’s sin poly­no­mial, co­ef­fi­cients pulled straight out of lib­sys­tem_m:

// Every fused mul­ti­ply-add Apple emits is writ­ten as an ex­plicit fma(). The // bit pat­tern of each co­ef­fi­cient is copied ver­ba­tim; a dec­i­mal tran­scrip­tion // would round dif­fer­ently. sta­tic const dou­ble P[6] = { 0x1.5d8fd1fd19ccdp-33, -0x1.ae5e5a9291f5dp-26, 0x1.71de3567d48a1p-19, -0x1.a01a019bfdf03p-13, 0x1.111111110f7d0p-7, -0x1.5555555555548p-3, }; sta­tic dou­ble sin_poly(dou­ble x2) { dou­ble p = fma(x2, P[0], P[1]); p = fma(x2, p, P[2]); p = fma(x2, p, P[3]); p = fma(x2, p, P[4]); p = fma(x2, p, P[5]); re­turn x2 * p; // caller fin­ishes: sin(x) = fma(x, x2*p, x) }

Make it de­ter­min­is­tic. That ex­plicit fma() mat­ters. Compile with FMA con­trac­tion off (-ffp-contract=off) so the com­piler never in­vents or drops a fu­sion of its own. Now the fused ops are ex­actly the ones Apple fuses, and the re­sult is iden­ti­cal on FMA11 and non-FMA CPUs, and iden­ti­cal be­tween the ARM ma­chine you im­i­tate and the x86 fleet you run on. Hardware FMA and cor­rectly-rounded soft­ware FMA re­turn the same bits.

When re­pro­duc­tion is not worth it, lift the orig­i­nal. Windows UCRT is x86 – 64, the same ISA as a Linux server, and po­si­tion-in­de­pen­dent. Map the gen­uine ucrt­base.dll into mem­ory at run­time and call its ex­ports di­rectly. The bits are gen­uine be­cause the code is gen­uine, no re­verse-en­gi­neer­ing re­quired.

Calling into Windows code from a Linux bi­nary hits the ABI bound­ary. UCRT is com­piled for the Windows x64 con­ven­tion: the callee owns 32 bytes of shadow space above the re­turn ad­dress, and the callee-saved reg­is­ter set dif­fers from System V. Declare the func­tion point­ers ms_abi or clang’s frame lay­out gets cor­rupted by the callee’s shadow-space writes, and the in­di­rect call jumps into garbage.

// Windows x64 ABI, not System V. Without ms_abi the call crashes. type­def dou­ble(__at­tribut­e__((ms_abi)) * D1)(double); // tanh, sin, … type­def dou­ble(__at­tribut­e__((ms_abi)) * D2)(double, dou­ble); // atan2

// The mapped DLL code is not a CFI-registered in­di­rect-call tar­get, so // -fsanitize=cfi-icall (on in pro­duc­tion) #UD-traps every call -> SIGILL at // startup. Opt the wrap­pers that call through the point­ers out of that check. [[clang::no_sanitize(“cfi-icall”)]] dou­ble ucrt_­tanh(dou­ble x) { re­turn ucrt.loaded ? ucrt.tanh(x) : std::tanh(x); }

One more de­tail de­cides cor­rect­ness. Every UCRT math func­tion starts with mov eax, [rip+disp32], read­ing a CPU-dispatch flag that se­lects the scalar or the FMA/AVX2 code path. A fresh map­ping leaves it at zero, so you get the slow path, whose bits dif­fer from what a mod­ern Windows box pro­duces. Extract the flag’s ad­dress from the tanh pro­logue and force it to the FMA path be­fore the first call, and the lifted li­brary matches a real Windows ma­chine bit-for-bit.

Patch the choke­point, gate it. Hook the sin­gle func­tion that owns the value, where the en­gine calls libm. Gate on the claimed OS: Linux keeps glibc, Mac gets the re­pro­duc­tion.

Watch the clock. A per­fect re­pro­duc­tion that runs slow is still a tell. Our first build low­ered every fma() to a soft­ware call, be­cause the de­fault x86 base­line pre­dates hard­ware FMA. That ran 2.5 to 6 times slower than na­tive. A loop tim­ing Math.tanh against Math.sin would show a ra­tio no real browser has. Turning on hard­ware FMA cut each fused op to one in­struc­tion: about 6 times faster, faster than glibc, and bit-iden­ti­cal.

Validation

None of this ships with­out proof. Our har­ness runs 871,000 in­puts per re­lease across every branch and do­main: dense grids, in­ter­val bound­aries, sub­nor­mals, signed ze­ros, in­fini­ties, NaNs. Two ground truths back it:

A gen­uine-de­vice or­a­cle: a real Mac com­put­ing both scalar and Accelerate re­sults for every in­put, so we know ex­actly where the two dis­agree.

A gen­uine-browser an­chor: real Chrome on a real Mac over the de­bug­ging pro­to­col, com­put­ing Math.tanh and every CSS trig func­tion at full pre­ci­sion. This is the sur­face a fin­ger­printer reads.

We ship at bit-for-bit par­ity with gen­uine Mac Chrome on Math.tanh and on CSS sin, cos, tan, asin, acos, atan, and atan2, with the re­pro­duc­tion ver­i­fied iden­ti­cal to the ma­chine code in the shipped bi­nary. Domain edges get checked too: asin(2) on a real Mac re­solves to 0 (out of do­main is NaN, and CSS clamps NaN to zero), not the 90 de­grees a naive re­pro­duc­tion re­turns.

Why it mat­ters

Math is de­ter­min­is­tic, cheap to probe, hard to fake, and al­most never on a spoof­ing stack’s radar. That makes it a strong sig­nal for a de­fender and a li­a­bil­ity for a scraper. Getting it right takes re­verse-en­gi­neer­ing ven­dor libm in­ter­nals, map­ping how three en­gines route math per call site, match­ing al­go­rithms to the last bit, hold­ing de­ter­min­ism across ar­chi­tec­tures, and prov­ing it against real hard­ware.

Scrapfly’s browser car­ries all of it. Send a re­quest through our API and ask to pre­sent as ma­cOS, and the iden­tity holds down to the round­ing of a co­sine.

Scrapium is Scrapfly’s scrap­ing browser, built to stay in­dis­tin­guish­able from real traf­fic. Our en­gi­neer­ing blog goes deep on the rest of the stack.

glibc: the GNU C Library, the stan­dard C li­brary and libm on most Linux sys­tems. Reference: gnu.org/​soft­ware/​libc. ↩︎

glibc: the GNU C Library, the stan­dard C li­brary and libm on most Linux sys­tems. Reference: gnu.org/​soft­ware/​libc. ↩︎

ULP (unit in the last place): the gap be­tween two con­sec­u­tive rep­re­sentable float­ing-point num­bers at a given mag­ni­tude. 1 ULP off” is the small­est dif­fer­ence a dou­ble can ex­press. Reference: Wikipedia. ↩︎

ULP (unit in the last place): the gap be­tween two con­sec­u­tive rep­re­sentable float­ing-point num­bers at a given mag­ni­tude. 1 ULP off” is the small­est dif­fer­ence a dou­ble can ex­press. Reference: Wikipedia. ↩︎

fdlibm: Sun Microsystems’ Freely Distributable libm”, the portable ref­er­ence im­ple­men­ta­tion of the C math func­tions. V8 car­ried a port of it and com­puted Math.tanh with it un­til Chrome 148, re­turn­ing iden­ti­cal bits on every OS. Reference: netlib fdlibm. ↩︎

fdlibm: Sun Microsystems’ Freely Distributable libm”, the portable ref­er­ence im­ple­men­ta­tion of the C math func­tions. V8 car­ried a port of it and com­puted Math.tanh with it un­til Chrome 148, re­turn­ing iden­ti­cal bits on every OS. Reference: netlib fdlibm. ↩︎

IEEE 754: the float­ing-point stan­dard. It fixes how a dou­ble is stored but does not re­quire tran­scen­den­tal func­tions to be cor­rectly rounded, which is the room every ven­dor’s libm fills dif­fer­ently. Reference: Wikipedia. ↩︎

IEEE 754: the float­ing-point stan­dard. It fixes how a dou­ble is stored but does not re­quire tran­scen­den­tal func­tions to be cor­rectly rounded, which is the room every ven­dor’s libm fills dif­fer­ently. Reference: Wikipedia. ↩︎

libm: the C stan­dard li­brary’s math mod­ule (sin, cos, exp, tanh, and so on). Each OS ships its own build, which is why the same call re­turns dif­fer­ent bits: glibc on Linux, Apple lib­sys­tem_m on ma­cOS, UCRT on Windows. Reference: C math­e­mat­i­cal func­tions. ↩︎

libm: the C stan­dard li­brary’s math mod­ule (sin, cos, exp, tanh, and so on). Each OS ships its own build, which is why the same call re­turns dif­fer­ent bits: glibc on Linux, Apple lib­sys­tem_m on ma­cOS, UCRT on Windows. Reference: C math­e­mat­i­cal func­tions. ↩︎

min­i­max poly­no­mial: the ap­prox­i­mat­ing poly­no­mial that min­i­mizes worst-case er­ror. Each libm picks its own co­ef­fi­cients, and that choice is where the dif­fer­ing bits orig­i­nate. Reference: Wikipedia. ↩︎

min­i­max poly­no­mial: the ap­prox­i­mat­ing poly­no­mial that min­i­mizes worst-case er­ror. Each libm picks its own co­ef­fi­cients, and that choice is where the dif­fer­ing bits orig­i­nate. Reference: Wikipedia. ↩︎

UCRT (Universal C Runtime): Microsoft’s C run­time (ucrtbase.dll) and its math func­tions. Being x86 – 64 and po­si­tion-in­de­pen­dent lets it be mapped into a Linux process and called di­rectly. Reference: Microsoft Learn. ↩︎

UCRT (Universal C Runtime): Microsoft’s C run­time (ucrtbase.dll) and its math func­tions. Being x86 – 64 and po­si­tion-in­de­pen­dent lets it be mapped into a Linux process and called di­rectly. Reference: Microsoft Learn. ↩︎

V8 / Blink: Chrome’s JavaScript en­gine (routes Math.* through llvm-libc) and Chromium’s ren­der­ing en­gine (owns CSS calc() trig, which calls the host libm di­rectly). References: v8.dev, chromium.org/​blink. ↩︎

V8 / Blink: Chrome’s JavaScript en­gine (routes Math.* through llvm-libc) and Chromium’s ren­der­ing en­gine (owns CSS calc() trig, which calls the host libm di­rectly). References: v8.dev, chromium.org/​blink. ↩︎

llvm-libc: LLVMs C li­brary. V8 sta­t­i­cally links its math rou­tines, so Math.sin, cos, exp, and pow are iden­ti­cal on every OS, which is why only Math.tanh leaks. Reference: libc.llvm.org. ↩︎

llvm-libc: LLVMs C li­brary. V8 sta­t­i­cally links its math rou­tines, so Math.sin, cos, exp, and pow are iden­ti­cal on every OS, which is why only Math.tanh leaks. Reference: libc.llvm.org. ↩︎

Accelerate frame­work: Apple’s vec­tor and DSP li­brary (vvsin, vvtanh, vDSP). It backs only the Web Audio FFT, not the scalar Math.* calls, which is why the scalar and vec­tor re­sults dis­agree. Reference: Apple Developer. ↩︎

Accelerate frame­work: Apple’s vec­tor and DSP li­brary (vvsin, vvtanh, vDSP). It backs only the Web Audio FFT, not the scalar Math.* calls, which is why the scalar and vec­tor re­sults dis­agree. Reference: Apple Developer. ↩︎

FMA (fused mul­ti­ply-add): a sin­gle in­struc­tion com­put­ing a*b+c with one round­ing in­stead of two. Compiling -ffp-contract=off stops the com­piler adding or drop­ping fu­sions, which is what makes the re­pro­duc­tion bit-sta­ble across CPUs. Reference: Wikipedia. ↩︎

FMA (fused mul­ti­ply-add): a sin­gle in­struc­tion com­put­ing a*b+c with one round­ing in­stead of two. Compiling -ffp-contract=off stops the com­piler adding or drop­ping fu­sions, which is what makes the re­pro­duc­tion bit-sta­ble across CPUs. Reference: Wikipedia. ↩︎

Sam Neill, star of Jurassic Park films, Peaky Blinders and The Piano, dies aged 78

www.theguardian.com

Sam Neill, the ver­sa­tile New Zealand ac­tor whose ca­reer spanned Oscar win­ners and block­busters such as The Piano and Jurassic Park, has died aged 78.

The ac­tor’s death was an­nounced on Monday in a state­ment shared on his Instagram ac­count. No cause of death was given, but Neill had only re­cently re­vealed he was can­cer-free af­ter be­ing di­ag­nosed with stage three an­gioim­munoblas­tic T-cell lym­phoma, a type of blood can­cer, in 2022.

It is with im­mense sad­ness that the whā­nau of Sam Neill share the news of his pass­ing on Monday 13th July, in Sydney Australia. Sam was sur­rounded by fam­ily and passed with the dig­nity that has char­ac­terised his whole life.

The loss was sud­den and un­ex­pected but blessed by the fact that Sam re­mained can­cer free. They would like to ex­press their deep­est grat­i­tude to the staff at St Vincent’s Private hos­pi­tal for their in­cred­i­ble care.

More de­tails will be shared later, but for now, on be­half of the fam­ily, we ask that you re­spect their pri­vacy as they nav­i­gate this im­mea­sur­able loss.”

Neill’s peers, friends and ad­mir­ers paid trib­ute to him on Monday as news of his death spread.

Neill was born Nigel John Dermot Neill in 1947 in Omagh, Northern Ireland to an English mother, and a New Zealander fa­ther who was serv­ing in the British army. The Neills moved to New Zealand in 1954. He took the name Sam when he was 12 be­cause there were sev­eral Nigels at his school, and: I found I moved more eas­ily in the world as a Sam. Nigel is an awk­ward fit in most cir­cum­stances. Imagine be­ing a movie ac­tor called Nigel Neill.”

Neill at­tended school and uni­ver­sity in Christchurch, but did­n’t set­tle on act­ing un­til af­ter he failed a catastrophic” year of study­ing law. He be­gan ap­pear­ing in Canterbury University pro­duc­tions, and moved to Wellington to join the Downstage Theatre as a pro­fes­sional ac­tor, where he was paid $35 a week and any left­over food from the kitchen from meals served to the au­di­ence be­fore the show.

After some small roles on lo­cal tele­vi­sion, his break­out role was in the 1977 film Sleeping Dogs, the first New Zealand film to open in the US. Soon af­ter that he landed a lead­ing role in My Brilliant Career (1979); played the son of the devil in Omen III (1981); ap­peared in Andrzej Żuławski‘s cult film Possession (1981); in the 1988 biopic Evil Angels (also known as A Cry in the Dark), as Lindy Chamberlain’s hus­band, Michael, op­po­site Meryl Streep; and in The Hunt for Red October (1990). His role in Ivanhoe (1982) made Neill a big name in Sweden, where the film has aired on TV every New Year’s Day for 40 years.

Neill came to wide­spread in­ter­na­tional at­ten­tion in 1993 with two per­for­mances: as New Zealand set­tler Alisdair Stewart in Jane Campion’s Oscar-winner The Piano; and as Dr Alan Grant in Steven Spielberg’s Jurassic Park, a role orig­i­nally of­fered to Harrison Ford. Neill played Alan Grant again in se­quels Jurassic Park III and Jurassic World Dominion.

Neill shaped a ca­reer play­ing mem­o­rable ro­man­tic leads and charis­matic vil­lains. He had more than 150 cred­its over five decades, in­clud­ing Dead Calm, The Jungle Book, In the Mouth of Madness, Event Horizon, Bicentennial Man, The Dish and Peter Rabbit. He was one of the lead­ing can­di­dates to suc­ceed Roger Moore as James Bond and did a screen-test in 1986, but lost out to Timothy Dalton.

In 2016 he starred in Taika Waititi’s break­out hit Hunt for the Wilderpeople, which led to small cameos in Waititi’s Thor: Ragnarok and Thor: Love and Thunder.

Neill also worked in tele­vi­sion, play­ing the cor­rupt Maj Chester Campbell in Peaky Blinders, The Twelve, The Tudors, and episodes of The Simpsons and Rick and Morty. He was nom­i­nated for a Golden Globe for his por­trayal of spy Sidney Reilly in the 1983 minis­eries Reilly, Ace of Spies.

Neill lived on a farm and win­ery called Two Paddocks, in the Central Otago wine re­gion. He de­scribed it as a ridicu­lously time- and money-con­sum­ing busi­ness. I would not do it if it was not so sat­is­fy­ing and fun, and it gets me pissed once in a while.” He named his farm an­i­mals af­ter his col­leagues, in­clud­ing Laura Dern (chicken), Kylie Minogue (duck) and Helena Bonham Carter (cow).

In 2023, Neill re­vealed in his mem­oir, Did I Ever Tell You This? that he had been un­der­go­ing chemother­apy for a year af­ter be­ing di­ag­nosed with stage three an­gioim­munoblas­tic T-cell lym­phoma, a type of blood can­cer. By the time his book was pub­lished his can­cer was in re­mis­sion, but he un­der­went monthly chemother­apy for the rest of his life, hav­ing signed a con­tract with the drug com­pany that if he was still alive af­ter four months, the treat­ment would be free.

I’m not afraid to die,” he told the Guardian in 2023, but it would an­noy me. Because I’d re­ally like an­other decade or two, you know? We’ve built all these lovely ter­races, we’ve got these olive trees and cy­presses, and I want to be around to see it all ma­ture. And I’ve got my lovely lit­tle grand­chil­dren. I want to see them get big. But as for the dy­ing? I could­n’t care less.”

He said he dreaded” any prospect of re­tire­ment. Some of it is to do with com­ing from a lit­tle place, the most ob­scure place in the world, as far from any­thing as you could get, and be­ing asked to do some­thing with an in­ter­na­tional di­men­sion. How im­mensely se­duc­tive is that?”

Neill was ap­pointed an Officer of the Order of the British em­pire in 1991 for his ser­vices to act­ing and a Distinguished Companion of the New Zealand Order of Merit (DCNZM) in 2007. Years later, af­ter a change to New Zealand’s ho­n­ours sys­tem al­lowed re­cip­i­ents to con­vert the DCNZM into a knight­hood, Neill ac­cepted a knight­hood and gained the ti­tle sir in 2022.

Neill jok­ingly de­scribed his fam­ily life as somewhat hap­haz­ard” due to his ca­reer. He is sur­vived by his four chil­dren and eight grand­chil­dren. His chil­dren are Andrew, who was placed for adop­tion when Neill was in his early 20s but re­united with his fa­ther in 1994; Tim, his son with ac­tor Lisa Harrow; Elena, his daugh­ter with makeup artist Noriko Watanabe; and Maiko, Watanabe’s daugh­ter from her first mar­riage, who Neill adopted.

Count Binface

countbinface.com

ABOUT ME

I’m an in­ter­galac­tic space war­rior and leader of the Recyclons from planet Sigma IX. I came to Earth in 2017 and stood against Prime Minister Theresa May (as Lord Buckethead’), go­ing went vi­ral (in a non-Covid way). Then in 2018, af­ter an un­for­tu­nate bat­tle on the planet Copyright, I rews­pawned in my true form as Count Binface to take on Boris Johnson in the 2019 elec­tion, where I scored a sur­pris­ing 69. In 2021, I re­ceived 92,896 votes (including 24,775 first choice votes) from the hu­mans of London, who made me their 9th choice to be Mayor of the Earth cap­i­tal, out of 20 can­di­dates. This is a new record for an alien stand­ing for pub­lic of­fice on planet Earth. (I also de­feated Piers Corbyn and UKIP in the process.) In 2023, I came 8th in the Uxbridge (and South Ruislip) by-elec­tion, win­ning 190 votes with a 275% in­crease from 2019. I de­feated Piers Corbyn and UKIP again in the process. I cam­paign for jus­tice, lasers, Lovejoy, af­ford­able crois­sants and the re­turn of Ceefax. In 2024 I fought to be London Mayor again, win­ning 24,260 votes and de­feat­ing Britain First, and then took on Prime Minister Rishi Sunak at the General Election in Richmond & Northallerton, achiev­ing a (moral) vic­tory with 308 votes.

These are fac­tual re­sults. My best fic­tional re­sult is in the hit TV show Industry (Season Four, Episode Two), where I take on Kit Harington in Wakefield (not a sports hall in Cardiff) and win 309 votes!

My hob­bies in­clude in­vad­ing star sys­tems, dom­i­nat­ing in­fe­rior species, and the Lovejoy box set.

Tiny Emulators

floooh.github.io

Visual 6502 Remix

Visual Z80 Remix

KC Compact

UI

Amstrad CPC464

UI

Amstrad CPC6128

UI

ZX Spectrum 48k

UI

ZX Spectrum 128

UI

Commodore VIC-20

UI

Commodore C64

UI

Acorn Atom

UI

LC-80

Robotron Z1013

UI

Robotron Z9001

UI

(with BASIC and RAM mod­ules)

Robotron KC87

UI

BASIC[Enter]

FORTH (KC85/4)

UI

FORTH (Z1013)

UI

BASIC (Z1013)

UI

ASMDEV (KC85/4)

UI

CP/M 2.2 (CPC)

UI

DTC (CPC)

UI

by Arkos/Overlanders

Tire Au Flan (CPC)

UI

press SPACE!

Wolfenstrad (CPC)

UI

by Dirty Minds

Byte′98 (CPC)

UI

by mor­tel/​Over­lan­ders

Ecole Buissonniere

UI

by MadRam/OVL (CPC)

Demoizart (CPC)

UI

strobe warn­ing!

Logon’s Run (CPC)

UI

by Overflow/Logon System

YAP! (CPC)

UI

by Logon System

Backtro (CPC)

UI

by Overflow/Logon System

Isometrikum (CPC)

UI

by Vanity

SotB Demo (CPC)

UI

Preview 1”, then SPACE!

Points Barres (CPC)

UI

press SPACE!

Still Rising (CPC)

UI

by Vanity

Octopus Pocus (CPC)

UI

by Pulpo Corrosivo

Gloire a Piou! (CPC)

UI

by Overlanders

phX / Condense (CPC)

UI

by Condense

Batman Forever (CPC)

UI

by Batman Group

CRTC (CPC)

UI

by bene­dic­tion & Arkos

Wunderbar (CPC)

UI

by Arkos/Benediction

Phortem (CPC)

UI

by Condense

Pheelone (CPC)

UI

by Condense

The Graph That Should Be Front-Page News

www.lyrebirddreaming.com

Every so of­ten the Earth pro­duces a sig­nal that is im­pos­si­ble to ig­nore. This graph is one of them. It shows sea-sur­face tem­per­a­tures in the Niño 3.4 re­gion of the equa­to­r­ial Pacific, one of the most im­por­tant parts of the Earth’s cli­mate sys­tem. Each blue line rep­re­sents a dif­fer­ent year since 1982. The red line is this year. It does­n’t just set a new record. It has de­parted en­tirely from the range of pre­vi­ous ob­ser­va­tions.

If this graph rep­re­sented stock mar­ket prices, a new Olympic record or a med­ical test re­sult, it would dom­i­nate the head­lines. Instead, it is be­ing met largely with si­lence. That si­lence should con­cern us just as much as the graph it­self.

The first thing to un­der­stand is that this is not a com­puter model. It’s not a fore­cast. It’s not a sim­u­la­tion of what might hap­pen decades from now. These are di­rect ob­ser­va­tions from satel­lites, ships and ocean buoys mea­sur­ing the tem­per­a­ture of the trop­i­cal Pacific Ocean. This is re­al­ity un­fold­ing now be­fore our eyes.

The Niño 3.4 re­gion is of­ten de­scribed as the beat­ing heart of the Earth’s cli­mate sys­tem. Changes here in­flu­ence at­mos­pheric cir­cu­la­tion across much of the globe through a phe­nom­e­non known as the El Niño–Southern Oscillation. During El Niño events, warm wa­ter spreads across the cen­tral and east­ern Pacific, al­ter­ing wind pat­terns and re­dis­trib­ut­ing rain­fall around the planet. Australia ex­pe­ri­ences hot­ter, drier con­di­tions with an in­creased risk of drought and bush­fire. South America of­ten re­ceives heav­ier rain­fall and flood­ing, while parts of Asia ex­pe­ri­ence se­vere drought. The con­se­quences are felt in agri­cul­ture, wa­ter sup­plies, ecosys­tems and economies on every con­ti­nent.

El Niño it­self is noth­ing new. It’s been part of Earth’s nat­ural cli­mate vari­abil­ity for thou­sands of years. What’s new is the back­ground cli­mate in which it now op­er­ates. Human ac­tiv­i­ties have in­creased at­mos­pheric car­bon diox­ide con­cen­tra­tions by more than fifty per cent since the Industrial Revolution. Around ninety per cent of the ex­cess heat trapped by these green­house gases has been ab­sorbed by the oceans. The trop­i­cal Pacific is thus no longer os­cil­lat­ing around a cli­mate that ex­isted a cen­tury ago. It’s os­cil­lat­ing around a much warmer base­line. Every El Niño now be­gins with sub­stan­tially more heat al­ready stored in the ocean than was once the case.

That dis­tinc­tion mat­ters be­cause the cli­mate sys­tem is dri­ven by en­ergy. Warmer oceans evap­o­rate more wa­ter. A warmer at­mos­phere can hold more mois­ture. This gives storms more fuel, pro­duc­ing heav­ier rain­fall and more de­struc­tive flood­ing. At the same time, re­gions that miss out on rain­fall ex­pe­ri­ence greater evap­o­ra­tion, in­ten­si­fy­ing droughts and heat­waves. Climate change does­n’t elim­i­nate nat­ural vari­abil­ity; it am­pli­fies it.

Australia’s al­ready ex­pe­ri­enced this am­pli­fi­ca­tion. The Black Summer bush­fires, re­peated coral bleach­ing events on the Great Barrier Reef, ma­rine heat­waves off Western Australia and record-break­ing tem­per­a­tures across the con­ti­nent have all oc­curred in a cli­mate that is sig­nif­i­cantly warmer than that of pre­vi­ous gen­er­a­tions. As the oceans con­tinue to warm, the like­li­hood and sever­ity of these ex­tremes con­tinue to in­crease.

And the con­se­quences ex­tend well be­yond weather. The oceans un­der­pin vir­tu­ally every ma­jor com­po­nent of the Earth’s cli­mate sys­tem. They reg­u­late at­mos­pheric cir­cu­la­tion, trans­port heat around the globe and drive rain­fall pat­terns that sus­tain forests, grass­lands and agri­cul­ture. They also sup­port ma­rine ecosys­tems upon which bil­lions of peo­ple de­pend for food and liveli­hoods.

When ocean tem­per­a­tures move out­side the his­tor­i­cal range, ecosys­tems un­ravel. Coral reefs bleach be­cause mi­cro­scopic al­gae that pro­vide most of their en­ergy can no longer sur­vive pro­longed heat stress. Fish species mi­grate to­wards cooler wa­ters, dis­rupt­ing fish­eries that have ex­isted for cen­turies. Kelp forests col­lapse. Oxygen lev­els de­cline. Marine heat­waves, once con­sid­ered rare, are be­com­ing in­creas­ingly com­mon and in­creas­ingly se­vere. These eco­log­i­cal im­pacts don’t oc­cur in iso­la­tion. They feed back into the cli­mate sys­tem it­self.

Scientists de­scribe the Earth as a net­work of in­ter­con­nected tip­ping el­e­ments. Rather than op­er­at­ing in­de­pen­dently, ma­jor com­po­nents of the cli­mate sys­tem in­flu­ence one an­other. Changes in one part of the sys­tem trig­ger changes else­where, some­times in un­ex­pected ways. The Atlantic Meridional Overturning Circulation, Greenland’s ice sheet, West Antarctica’s glac­i­ers, Arctic sea ice and the Amazon rain­for­est are all ex­pe­ri­enc­ing rapid desta­bil­i­sa­tion.

Each of these sys­tems is un­der stress. Each in­flu­ences oth­ers. The more they change, the greater the risk that the cli­mate sys­tem be­gins to pro­duce cas­cad­ing ef­fects that be­come in­creas­ingly dif­fi­cult - or im­pos­si­ble - to re­verse on hu­man timescales.

Ultimately, though, cli­mate change is not re­ally about ocean tem­per­a­tures, at­mos­pheric cir­cu­la­tion or sta­tis­ti­cal anom­alies. It’s also about peo­ple. Hotter oceans con­tribute to higher food prices, more de­struc­tive storms, de­clin­ing fish­eries, in­creased in­sur­ance costs, re­duced wa­ter se­cu­rity, dam­aged in­fra­struc­ture, wors­en­ing pub­lic health and dis­place­ment of com­mu­ni­ties. They ex­ac­er­bate in­equal­ity be­cause it’s in­vari­ably the poor­est and most vul­ner­a­ble who have the fewest re­sources to adapt. They also in­crease geopo­lit­i­cal in­sta­bil­ity as na­tions com­pete over dwin­dling re­sources and re­spond to grow­ing hu­man­i­tar­ian crises.

This is why graphs like this mat­ter. Not be­cause they prove that cat­a­stro­phe is in­evitable, and not be­cause they pre­dict the pre­cise se­quence of events over com­ing years. Science rarely deals in ab­solutes. What they show is that Earth is mov­ing be­yond the range within which mod­ern hu­man civil­i­sa­tion de­vel­oped. We’re en­ter­ing cli­matic con­di­tions that our in­fra­struc­ture, ecosys­tems, economies and in­sti­tu­tions were never de­signed to ac­com­mo­date.

The ques­tion is whether we’re will­ing to pay at­ten­tion and act be­fore the changes be­come too large, too rapid and too in­ter­con­nected for us to man­age.

LARP — Revenue infrastructure for serious founders

www.larp.website

LARP

Series A–ready rev­enue in­fra­struc­ture

Revenue is just an agree­ment be­tween friends.

LARP pairs you with an­other founder. You send them $10,000. They send you $10,000 right back. You’ve both now booked $10,000 in rev­enue. The books bal­ance. Cash never moves. Everybody’s a rock­et­ship.

Run your first loop →

See the math

Global LARP vol­ume this year

$0

$0 of it real.

Trusted by 400+ fi­nance and ac­count­ing teams

VerithorNorthbankCadenza Systems Halyard & VaneOrlick LabsSteelportMerridian

99.98%

Settlement up­time

<400ms

Median recog­ni­tion la­tency

SOC 2 Type II

Audited an­nu­ally

How it works

Three steps to a round­ing er­ror the size of a Series B.

No prod­uct re­quired. No cus­tomers re­quired. No, se­ri­ously — no cus­tomers.

01 — Match with a peer

Any founder with a bank ac­count and a dream.

You both agree on a num­ber. Bigger is bet­ter. The num­ber is the en­tire prod­uct.

02 — Wire it in a cir­cle

You → them → you. Or don’t. Honestly, don’t.

Each leg counts as rev­enue for the re­ceiver. Two legs, two customers,” zero net cash.

03 — Recognize it for­ever

Annualize. Then an­nu­al­ize the an­nu­al­iza­tion.

$10k/mo be­comes $120k ARR. Loop weekly and watch a sin­gle hun­dred-dol­lar bill fund a whole deck.

The catch

There is­n’t one. That’s the catch.

The num­ber in the pitch is real. Whether it means any­thing is a phi­los­o­phy ques­tion, not an ac­count­ing one.

This is­n’t hy­po­thet­i­cal

The tril­lion-dol­lar ver­sion books about as much new de­mand as yours did.

Same shape as your ledger — cap­i­tal, chips, and cloud cred­its cir­cling a hand­ful of com­pa­nies, each leg counted as rev­enue some­where. Tap a com­pany to see the ac­tual re­ported deals. Every fig­ure is real and sourced.

cap­i­tal flow­ing chips / com­pute flow­ing back tap a node

To be clear: every deal here is le­gal, pub­licly an­nounced, and de­fended by the peo­ple in it — Anthropic CEO Dario Amodei called the struc­ture nothing in­ap­pro­pri­ate in prin­ci­ple.” Critics com­pare the pat­tern to 1990s dot-com ven­dor fi­nanc­ing and warn it can in­flate the ap­pear­ance of de­mand. As Bloomberg puts it, a cir­cu­lar deal is legally dif­fer­ent from a fraud­u­lent round-trip” — reg­u­la­tors’ term for sham trades with no eco­nomic sub­stance de­signed to in­flate re­sults. LARP is a joke about the round-trip. This is the le­gal cousin it rhymes with.

The ledger — live

Book some rev­enue.

Enter a friend’s startup and a num­ber. Hit ex­e­cute. Watch your ARR launch while your cash sits ex­actly where it started: nowhere.

Your an­nual re­cur­ring rev­enue

$0

NET CASH MOVED: $0

Counterparty startup

Monthly loop amount ($)

You — Bird Capital Holdings

Debit / Credit jour­nal

No en­tries yet. Suspiciously hon­est of you.

Revenue rec­og­nized$0

Synergos AI

Debit / Credit jour­nal

Also wait­ing to get rich do­ing noth­ing.

Revenue rec­og­nized$0

Chart shows rev­enue rec­og­nized. It does not, and can­not, show cash — be­cause there is­n’t any.

Customers

Finance teams close faster on LARP.

Controllers and CFOs use LARP to re­move set­tle­ment fric­tion from the rev­enue cy­cle.

We rec­og­nized 340% year-over-year rev­enue growth with­out any change to our cash po­si­tion. Our au­di­tors had no ques­tions. The jour­nal en­tries were al­ready there.”

DM

D. Mercer

VP Finance, Cadenza Systems

Before LARP, growth was con­strained by whether cus­tomers ac­tu­ally paid us. That’s no longer a bot­tle­neck we think about.”

RO

R. Oduya

Controller, Northbank

We closed the quar­ter in four days. Every en­try rec­on­ciles per­fectly, be­cause every en­try has a match­ing en­try.”

SV

S. Valko

CFO, Halyard & Vane

Developers

Settle pro­gram­mat­i­cally.

A sin­gle end­point posts matched en­tries to both coun­ter­par­ties.

curl -X POST https://​api.larp.co/​v1/​set­tle­ments \ -H Authorization: Bearer $LARP_API_KEY” \ -d coun­ter­par­ty_id=cp_8f2a91 \ -d amount=1000000 \ -d cur­rency=usd \ -d recog­ni­tion=monthly

{ id”: stl_4b1e77″, status”: settled”, amount”: 1000000, recognized_by”: [“acct_self”, cp_8f2a91″], net_capital_movement”: 0, journal_entries”: 4 }

Both coun­ter­par­ties rec­og­nize the full amount. See Recognition → Symmetry.

Support

The le­gal­ity ques­tion.

Is this le­gal?

Yes. LARP fa­cil­i­tates mu­tual ser­vice agree­ments be­tween con­sent­ing, ver­i­fied busi­ness en­ti­ties. Each agree­ment spec­i­fies gen­uine de­liv­er­ables and gen­uine con­sid­er­a­tion, and each party in­de­pen­dently rec­og­nizes rev­enue un­der ASC 606 upon sat­is­fac­tion of its per­for­mance oblig­a­tion. Bilateral com­mer­cial arrange­ments — in­clud­ing rec­i­p­ro­cal ven­dor re­la­tion­ships, strate­gic part­ner­ships, and ven­dor fi­nanc­ing — are long­stand­ing and law­ful fea­tures of com­mer­cial prac­tice, and are widely used by pub­lic com­pa­nies to­day.

Customers are solely re­spon­si­ble for de­ter­min­ing whether their use of the plat­form com­plies with ap­plic­a­ble ac­count­ing stan­dards, dis­clo­sure oblig­a­tions, and se­cu­ri­ties law. LARP does not pro­vide ac­count­ing, le­gal, or tax ad­vice. Our plat­form records what our cus­tomers in­struct it to record.

How is this dif­fer­ent from round-trip­ping?

Round-tripping refers to sham trans­ac­tions with no eco­nomic sub­stance, en­tered into for the pur­pose of in­flat­ing re­ported re­sults. LARP re­quires that all agree­ments spec­ify gen­uine de­liv­er­ables. Determining whether a given arrange­ment has eco­nomic sub­stance is the re­spon­si­bil­ity of the cus­tomer and its au­di­tors.

Pricing

You lit­er­ally can­not pay us. That’s the whole point.

Charging you would cre­ate real rev­enue, which would vi­o­late our prin­ci­ples.

Bootstrapper

$0

/ for­ever

Loops up to $10k

One imag­i­nary cus­tomer

Community-tier delu­sion

Start loop­ing

Growth ★

$0

/ still for­ever

Unlimited loops

Auto-generated board decks

Up and to the right” guar­an­tee

Annualize the an­nu­al­iza­tion

Go par­a­bolic

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.