10 interesting stories served every morning and every evening.

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.

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, be­cause every sub­agent has its own boot­strap cost, and the par­ent then con­sumes its 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.

The Fable lanes were smaller sam­ples, two runs for the floor and cache tasks and one for the multi-step task, so treat them as di­rec­tional con­fir­ma­tion rather than a sec­ond full study.

Part II. The mul­ti­pli­ers

The floor (above) ex­plains a ses­sion that starts lean and stays short.

Old and new apps, via modern coding agents

terrytao.wordpress.com

I have been in­ter­ested in ma­chine-as­sisted ways to do and teach math­e­mat­ics from as far back as 1999, when I started cod­ing sev­eral ap­plets in Java 1.0, both for my com­plex analy­sis and lin­ear al­ge­bra courses, as well as to vi­su­al­ize var­i­ous math­e­mat­i­cal ob­jects I was in­ter­ested in (such as hon­ey­combs or Besicovitch sets). This was mod­er­ately suc­cess­ful; but the ap­plets were time-con­sum­ing to pro­gram. Eventually, the stan­dards for web pages stopped sup­port­ing this ver­sion of Java, and the ap­plets be­came non-func­tional.

However, in the last few days I have be­gun the process of mi­grat­ing much of my old web page and blog data to a more main­tain­able repos­i­tory, us­ing mod­ern AI as­sis­tance. As an ex­per­i­ment, I asked the agent to port my old ap­plets to a mod­ern sup­ported lan­guage (we landed on Javascript), and it man­aged to do so in a mat­ter of hours, with all of my old ap­plets now func­tional again, with even a few graph­i­cal up­grades (for in­stance, the Besicovitch set ap­plet is now col­orized, in con­trast to my orig­i­nal mono­chrome ver­sion). I am par­tic­u­larly pleased to see the hon­ey­comb ap­plet that I wrote with Allen Knutson in 1999 come back to life, as this was a par­tic­u­larly tricky one to code by hand:

Notoriously, LLM-based cod­ing agents can cre­ate var­i­ous bla­tant or sub­tle bugs in their code; but in the port­ing of these two dozen or so ap­plets, I could only find one mi­nor bug (the han­dling of a drag event in one of the com­plex analy­sis ap­plets had un­wanted be­hav­ior when drag­ging out­side of the main box), and in fact the agent iden­ti­fied two bugs in the orig­i­nal code that I was not aware of, so it ended up be­ing a net wash as far as code qual­ity was con­cerned. In any event, as these ap­plets are meant to be sec­ondary vi­sual aids rather than crit­i­cal com­po­nents of a math­e­mat­i­cal ar­gu­ment, the down­side risk of such bugs is rel­a­tively low.

The process was pain­less enough that I de­cided to also try cod­ing some new apps, in ad­di­tion to port­ing the old ones. Back in 1999 I had an am­bi­tious idea for a vi­su­al­iza­tion tool for spe­cial rel­a­tiv­ity; this was be­fore the re­lease of the soft­ware tool Inkscape, but the idea I had in mind was ba­si­cally Inkscape, but in Minkowski space”. I had even started writ­ing Java code for this app, but the code com­plex­ity be­came too much for me, and I aban­doned the pro­ject. However, af­ter a cou­ple hours of vibe cod­ing” with an AI agent, I was fi­nally able to gen­er­ate an ap­plet that matched the vi­sion I had back in 1999, which can now be found here. A sum­mary of the con­ver­sa­tion I had with the agent to gen­er­ate this code can be found here (it has been edited down to re­move a large num­ber of te­dious tech­ni­cal im­ple­men­ta­tion re­ports). While I have playtested the app some­what, I would be in­ter­ested in re­ceiv­ing fur­ther feed­back on this alpha” ver­sion of the ap­plet, as I am sure (especially given the LLM-generated na­ture of the code) that there are still some bugs and rough edges to be ironed out.

After writ­ing my blog post on the Gilbreath con­jec­ture pa­per ear­lier to­day, I re­al­ized that I could sim­i­larly ask the agent to code a vi­su­al­iza­tion tool for the Gilbreath con­jec­ture to ac­com­pany the pa­per and blog post. After an­other few hours of con­ver­sa­tion, this is now done; you can try out the vi­su­al­iza­tion here. Again, the pro­ce­dure was quite pain­less (see this tran­script of the process), and I think I may add such in­ter­ac­tive vi­su­al­iza­tions as sup­ple­ments for fu­ture pa­pers; as such sup­ple­ments are not mis­sion-crit­i­cal to the core of the pa­per, I again feel that the down­side risk of us­ing guided in­ter­ac­tion with LLM agents to gen­er­ate such vi­su­al­iza­tions is ac­cept­able.

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. ↩︎

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. ↩︎

Terminal emulator powered by libghostty

dakra.github.io

Table of Contents

1. Quick Start

1.1. Shell in­te­gra­tion at a glance 1.2. Input modes at a glance

1.1. Shell in­te­gra­tion at a glance

1.2. Input modes at a glance

2. Requirements

3. Installation

3.1. MELPA 3.2. use-pack­age with :vc (Emacs 30+) 3.3. use-pack­age with :load-path 3.4. Manual 3.5. Native mod­ule 3.6. Platform notes

3.6.1. Windows

3.1. MELPA

3.2. use-pack­age with :vc (Emacs 30+)

3.3. use-pack­age with :load-path

3.4. Manual

3.5. Native mod­ule

3.6. Platform notes

3.6.1. Windows

3.6.1. Windows

4. Building from source

4.1. Bundled ter­minfo

4.1. Bundled ter­minfo

5. Shell in­te­gra­tion

6. Input modes

6.1. Mode-switch key­bind­ings 6.2. Semi-char mode (default) 6.3. Char mode 6.4. Emacs mode 6.5. Copy mode 6.6. Mouse se­lec­tion 6.7. Line mode 6.8. Scrollback search out­side copy mode

6.1. Mode-switch key­bind­ings

6.2. Semi-char mode (default)

6.3. Char mode

6.4. Emacs mode

6.5. Copy mode

6.6. Mouse se­lec­tion

6.7. Line mode

6.8. Scrollback search out­side copy mode

7. Features

7.1. Terminal em­u­la­tion 7.2. Process model 7.3. Bookmarks 7.4. Links and file de­tec­tion 7.5. Clipboard 7.6. Input 7.7. Password prompt de­tec­tion 7.8. Shell in­te­gra­tion fea­tures 7.9. Rendering 7.10. Inline im­ages (Kitty graph­ics pro­to­col)

7.10.1. Limitations

7.11. Calling Elisp from the shell 7.12. Notifications and progress 7.13. Color palette

7.1. Terminal em­u­la­tion

7.2. Process model

7.3. Bookmarks

7.4. Links and file de­tec­tion

7.5. Clipboard

7.6. Input

7.7. Password prompt de­tec­tion

7.8. Shell in­te­gra­tion fea­tures

7.9. Rendering

7.10. Inline im­ages (Kitty graph­ics pro­to­col)

7.10.1. Limitations

7.10.1. Limitations

7.11. Calling Elisp from the shell

7.12. Notifications and progress

7.13. Color palette

8. TRAMP (Remote Terminals)

8.1. Remote shell in­te­gra­tion

8.1.1. Option 1: Automatic in­jec­tion (recommended for con­ve­nience) 8.1.2. Option 2: Manual setup (recommended for per­ma­nent re­mote hosts)

8.2. Remote xterm-ghostty ter­minfo

8.2.1. TRAMP-launched ghos­tel 8.2.2. Outbound ssh from a lo­cal ghos­tel buffer 8.2.3. Manual in­stall (no auto-ma­chin­ery) 8.2.4. Drop the Ghostty ad­ver­tise­ment en­tirely

8.1. Remote shell in­te­gra­tion

8.1.1. Option 1: Automatic in­jec­tion (recommended for con­ve­nience) 8.1.2. Option 2: Manual setup (recommended for per­ma­nent re­mote hosts)

8.1.1. Option 1: Automatic in­jec­tion (recommended for con­ve­nience)

8.1.2. Option 2: Manual setup (recommended for per­ma­nent re­mote hosts)

8.2. Remote xterm-ghostty ter­minfo

8.2.1. TRAMP-launched ghos­tel 8.2.2. Outbound ssh from a lo­cal ghos­tel buffer 8.2.3. Manual in­stall (no auto-ma­chin­ery) 8.2.4. Drop the Ghostty ad­ver­tise­ment en­tirely

8.2.1. TRAMP-launched ghos­tel

8.2.2. Outbound ssh from a lo­cal ghos­tel buffer

8.2.3. Manual in­stall (no auto-ma­chin­ery)

8.2.4. Drop the Ghostty ad­ver­tise­ment en­tirely

9. Configuration

9.1. Process and en­vi­ron­ment 9.2. Native mod­ule 9.3. TRAMP and re­mote 9.4. Rendering and per­for­mance 9.5. Images 9.6. Links, clip­board, and de­tec­tion 9.7. Password prompts 9.8. Notifications and progress 9.9. Input and in­ter­ac­tion 9.10. Line mode

9.1. Process and en­vi­ron­ment

9.2. Native mod­ule

9.3. TRAMP and re­mote

9.4. Rendering and per­for­mance

9.5. Images

9.6. Links, clip­board, and de­tec­tion

9.7. Password prompts

9.8. Notifications and progress

9.9. Input and in­ter­ac­tion

9.10. Line mode

10. Extensions

10.1. Evil-mode 10.2. Compilation mode

10.2.1. Live mode switch­ing 10.2.2. Keybindings (ghostel-compile-view-mode, also ac­tive dur­ing a read-only run) 10.2.3. Make com­pile / re­com­pile / pro­ject-com­pile use ghos­tel 10.2.4. Hooks for your own in­te­gra­tions

10.3. Eshell in­te­gra­tion 10.4. Comint in­te­gra­tion 10.5. Emacs Lisp in­put meth­ods

10.1. Evil-mode

10.2. Compilation mode

10.2.1. Live mode switch­ing 10.2.2. Keybindings (ghostel-compile-view-mode, also ac­tive dur­ing a read-only run) 10.2.3. Make com­pile / re­com­pile / pro­ject-com­pile use ghos­tel 10.2.4. Hooks for your own in­te­gra­tions

10.2.1. Live mode switch­ing

10.2.2. Keybindings (ghostel-compile-view-mode, also ac­tive dur­ing a read-only run)

10.2.3. Make com­pile / re­com­pile / pro­ject-com­pile use ghos­tel

10.2.4. Hooks for your own in­te­gra­tions

10.3. Eshell in­te­gra­tion

10.4. Comint in­te­gra­tion

10.5. Emacs Lisp in­put meth­ods

11. Commands

11.1. Sending in­put from Lisp 11.2. Project in­te­gra­tion

11.1. Sending in­put from Lisp

11.2. Project in­te­gra­tion

12. Running tests

13. Performance

13.1. Native vs Emacs PTY 13.2. Burst ab­sorp­tion (cat a 10 MB file) 13.3. Typing la­tency

13.1. Native vs Emacs PTY

13.2. Burst ab­sorp­tion (cat a 10 MB file)

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

Just a moment...

www.economist.com

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.