Infinite Mac: Turning To The Dark Side

tl;dr: No, not Windows¹, but I’ve decided to expand Infinite Mac to the the black hardware that Mac users secretly lusted after in the 80s and 90s: NeXT. There is now a runnable collection of all notable NeXTStep versions, going from the initial 0.8 preview in 1988 to the final O … | Continue reading


@blog.persistent.info | 1 month ago

Infinite Mac: The Case Of The Missing Text

I had previously mentioned that I ended up fixing some DingusPPC CPU emulation bugs. This was my first time working at this (lower) level of the Infinite Mac emulators, and I thought it would be interesting to write up such an investigation. There was an issue that was immediatel … | Continue reading


@blog.persistent.info | 2 months ago

Infinite Mac: DingusPPC Explorations

One of my goals for Infinite Mac is to learn more about computer architecture and other fundamentals. While fiddling with actual old hardware is not as interesting to me (the one classic Mac I own is a PowerBook 550c that I turn on about once a year), I do enjoy operating at lowe … | Continue reading


@blog.persistent.info | 5 months ago

Infinite Mac: Improved Persistence

Infinite Mac has supported a limited form of persistence since its initial launch. This was done by exporting the contents of the “Saved” folder in “The Outside World” to IndexedDB when the emulator was shut down. While this worked, it had several limitations: Saving was best-ef … | Continue reading


@blog.persistent.info | 8 months ago

20 Years of Blogging

The first proper blog post on this site was 20 years ago today. It lived under a different URL, I didn’t register persistent.info until later (when .info was a new-and-shiny top-level domain). It also looked different (I don’t have a screenshot of the first version, but I switche … | Continue reading


@blog.persistent.info | 8 months ago

Infinite Mac: Disks, CD-ROMs and Custom Instances

Here are a few highlights of what’s been happening with Infinite Mac since my last update. Improving Disk Abstractions My broad goal this time around was to make it easier to load external software. To lay the groundwork for this, I first needed to improve some of the disk abstra … | Continue reading


@blog.persistent.info | 9 months ago

Slack Canvas In The Streets, Quip In The Sheets

I finally got access to the recently-launched Slack canvas feature. This project was the last thing I worked on before I left Quip/Slack/Salesforce in April of 2022, and I was curious how it had evolved since then. Canvas started as a prototype in mid-2021 to reuse Quip technolog … | Continue reading


@blog.persistent.info | 10 months ago

10th Anniversary of Google Reader Shutdown

It doesn't feel like it's been 5 years since my last post about Reader, but I guess the past few years have suffered from time compression. For this anniversary I don't have any cool projects to unveil, but that's OK, because David Pierce wrote a great article – Who killed Google … | Continue reading


@blog.persistent.info | 10 months ago

Tailscale battery life instrumentation

I wrote a valedictory blog post about the instrumentation we're adding to the Tailscale client to get a handle on battery life issues. It's been an interesting "full-stack" project, involving thinking about cell phone internals, hacking on the Go standard library, and exp … | Continue reading


@blog.persistent.info | 1 year ago

You won't believe what this one weird ioctl will do

Darwin was one of the first things Apple open-sourced (24 years ago). It's been mostly a "throw it over the wall" approach, but being able to peek under the hood has been very handy. I wrote a short tailscale.dev blog post showing how we've been able to improve Tailscale's macOS … | Continue reading


@blog.persistent.info | 1 year ago

Infinite Mac: infinitemac.org

tl;dr: Infinite Mac has a new home at infinitemac.org. Using a new Emscripten port of Mini vMac, it is now able to run almost every notable version of Mac OS, from 1984’s System 1.0 to 2000’s Mac OS 9.0.4. The project is also now accepting donations (via GitHub Sponsors or PayPal … | Continue reading


@blog.persistent.info | 1 year ago

Reducing Tailscale’s Binary Size on macOS

One of the less visible changes in Tailscale v1.36 is that the macOS binary is 35MB smaller. I wrote a post on the Tailscale blog about the chance observation and investigations that led to this size win. If you're interested in this kind of low-level shennanigans, we are hir … | Continue reading


@blog.persistent.info | 1 year ago

How I Consume Mastodon

tl;dr: I use Masto Feeder to generate a nicely-formatted RSS feed of my timeline, and then I can read it in my preferred feed reader. A bit more than 10 years ago I wrote a post called “How I Consume Twitter”. It described how I contort Twitter to my completionist tendencies by g … | Continue reading


@blog.persistent.info | 1 year ago

Tailscale iOS and macOS Shortcuts

I worked on adding iOS and macOS Shortcuts support for Tailscale's latest release. I wrote a blog post with examples of shortcuts and automations that the Tailscale actions could be combined with. One that didn't make the cut was using sound recognition, for things like “In case … | Continue reading


@blog.persistent.info | 1 year ago

Places Mihai Has Committed Code From

I've been running lolcommits for 10 years, and it's captured some interesting moments from my time at Quip and Tailscale. I've put together a gallery, it was a fun nostalgia trip to revisit so many places and coworkers. | Continue reading


@blog.persistent.info | 1 year ago

Infinite Mac: 2022 In Review

I've come to think of Infinite Mac as my forever project. There's always something to work on, whether it's expanding the library, improving compatibility, adding more platforms, improving performance, debugging data structures, bridging APIs from 30 years ago with modern web pla … | Continue reading


@blog.persistent.info | 1 year ago

Tailscale Fast User Switching

Account switching is one of the less fun parts of modern computing -- for a while I had registered giveupandusemultiplebrowsers.com. Even when software tries to accomodate these scenarios, the heuristics for when to switch can be tricky, and in some cases require the user to main … | Continue reading


@blog.persistent.info | 1 year ago

If you wish to make a web SSH client from scratch, you must first invent the network stack

It was a lot of fun turning Brad's Taiscale-on-Wasm prototype into Tailscale SSH Console. I wrote a post for the Tailscale blog with more details (you can tell it wasn't ghost-written because it has my link-heavy style). Almost all of the development was in the open-source repo, … | Continue reading


@blog.persistent.info | 1 year ago

The Case of the Spiky File Descriptors

One of the things that attracted me to Tailscale was their in-depth technical blog posts, like Josh's hacking on Go internals to get iOS memory use down, or Dave's epic treatise on NAT traversal. It was therefore nice to be able to contribute a debugging story: The Case o … | Continue reading


@blog.persistent.info | 1 year ago

How Well Did the Original iPhone Sell?

At this year’s Code Conference Tim Cook discussed disagreements that he and Steve Jobs had, including whether to have a carrier subsidy for the iPhone: Cook reveals him and Jobs disagreed over launching the iPhone as subsidized by the carrier or via receiving a carrier revenue s … | Continue reading


@blog.persistent.info | 1 year ago

Infinite Mac on a (Virtual) LAN

tl;dr I’ve added a Cloudflare Durable Object-based LAN mode to Infinite Mac, allowing networked games of Marathon, Bolo and anything else that works over AppleTalk. To try it out, use demo.system7.app (or any other subdomain — it defines the “zone” where packets are broadcast and … | Continue reading


@blog.persistent.info | 1 year ago

Infinite Mac 7.5 Weeks Later

Infinite Mac has been quite a whirlwind. I wasn’t sure if it would reach the Mac (or retro computing) community, but it did, and went beyond that too, including to Ars Technica and Hacker News (twice). The most gratifying thing was seeing (and in some cases hearing from) people w … | Continue reading


@blog.persistent.info | 2 years ago

Infinite Mac: An Instant-Booting Quadra in the Browser

Comments | Continue reading


@blog.persistent.info | 2 years ago

A-12 Software Development Parallels

I recently finished reading From RAINBOW to GUSTO which describes the development of the A-12 high-speed reconnaisance plane (the predecessor to/basis for the somewhat better known SR-71 Blackbird). Though a bit different from the software history/memoirs that I've also enjoyed, … | Continue reading


@blog.persistent.info | 2 years ago

Communicating With a Web Worker Without Yielding To The Event Loop

I recently came across James Friends’s work on porting the Basilisk II classic Mac emulator to run in the browser. One thing that I liked about his approach is that it uses SharedArrayBuffer to allow the emulator to run in a worker with minimal modifications. This system can also … | Continue reading


@blog.persistent.info | 2 years ago

Archiving Mscape Software on GitHub

Mscape Software was the “label” that I used in my late teenage years for Mac shareware programs. While having such a fake company was (is?) a surprisingly common thing, it turned into a pretty real side-gig during 1999 to 2003. I spent a lot of my hobby programming time working o … | Continue reading


@blog.persistent.info | 2 years ago

Making Git Understand Classic Mac Resource Forks

For a (still in-progress) digital archiving project I wanted to create a Git repository with some classic Mac OS era software. Such software relies on resource forks, which sadly Git does not support. I looked around to see if others had run into this, and found git-resource-fork … | Continue reading


@blog.persistent.info | 3 years ago

Solving Bee: An Augmented Reality Tool for Spelling Bee

Like many others I’ve spent a lot of time over the past year playing the New York Times’ Spelling Bee puzzle. For those that are not familiar with it, it’s a word game where you’re tasked with finding as many words as possible that can be spelled with the given 7 letters, with th … | Continue reading


@blog.persistent.info | 3 years ago

The Case of the Missing Equals Sign

I was recently investigating suspiciously high CPU usage while typing in documents in Quip’s Mac app. We had recently switched to WKWebView, and this was happening in the “web content” process, suggesting that it was a JavaScript-related problem, or perhaps something related to t … | Continue reading


@blog.persistent.info | 3 years ago

Quip's TypeScript Migration

Quip did a wholesale migration to TypeScript around this time last year. Now that the dust has settled and we've lived with the consequences for a while, Rafael and I wrote a couple of blog posts about it all: Part one describes the process that we chose, and part two has som … | Continue reading


@blog.persistent.info | 3 years ago

In-Product Debugging Tools

I wrote a post on the Quip blog about the various in-product debugging tools that we've developed over the years. It's been very satisfying to make and use our tools over the years, I'm glad we're finally sharing some details about them. One of the many overlays we've created | Continue reading


@blog.persistent.info | 4 years ago

Accidental DDoSes I Have Known

A couple of weeks I was migrating some networking code in Quip's Mac app from NSURLConnection to NSURLSession when I noticed that requests were being made significantly more often than I was expecting. While this was great during the migration (since it made exercising that code … | Continue reading


@blog.persistent.info | 5 years ago

Some Observations Regarding JavaScriptCore's Supported Platforms

JavaScriptCore (JSC) is the JavaScript engine that powers WebKit (and thus Safari). I was recently browsing through its source and noticed a few interesting things: ARM64_32 Support Apple Watch Series 4 uses the S4 64-bit ARM CPU, but running in a mode where pointers are still 3 … | Continue reading


@blog.persistent.info | 5 years ago

Google Reader: A Time Capsule from 5 Years Ago

It's now been 5 years since Google Reader was shut down. As a time capsule of that bygone era, I've resurrected readerisdead.com to host a snapshot of what Reader was like in its final moments — visit http://readerisdead.com/reader/ to see a mostly-working Reader user interface. … | Continue reading


@blog.persistent.info | 5 years ago

Efficiently Loading Inlined JSON Data

I wrote up a post on the Quip blog about more efficiently embedding JSON data in HTML responses. The tl;dr is that moving it out of a JavaScript tag and parsing it separately with JSON.parse can significantly reduce the parse time for large data sizes. | Continue reading


@blog.persistent.info | 6 years ago

Understanding WebKit behavior via lldb

I recently ran into some puzzling WebKit scrolling behavior: child iframes mysteriously causing the main window to get scrolled. This was in the context of a Quip feature still under development, but I've recreated a simple test case for it, to make it easier to follow along. The … | Continue reading


@blog.persistent.info | 6 years ago

Disabling the click delay in UIWebView

Historically, one of the differences that made hybrid mobile apps feel a bit “off” was that there would be lag when handling taps on UI elements with a straightforward click event handler. Libraries such as Fastclick were created to mitigate this by using raw touch events to imme … | Continue reading


@blog.persistent.info | 7 years ago

Perils of Measuring Long Intervals with Performance.now()

I recently ran into an interesting quirk when using Performance.now() to measure long-ish intervals in Quip's web app. Since it does not seem to be broadly known, I thought I would document it. To mitigate the possibility of self-induced DDoS attacks, I recently added duplicate r … | Continue reading


@blog.persistent.info | 7 years ago

Avoiding Incremental Rendering in Hybrid Desktop Apps

I previously described how adding native popovers and modal dialogs to Quip’s hybrid desktop apps helped them to blend in and avoid the “uncanny valley” of web-based apps that don’t quite feel right. Another area that we focused on was the experience of creating a new window, esp … | Continue reading


@blog.persistent.info | 8 years ago

Grafting Local Static Resources onto Production

tl;dr: Using the webRequest Chrome extension API it is possible to “graft” development/localhost JavaScript and CSS assets on a production web service, thus allowing rapid debugging iteration against real production data sets. Demo site and extension. During the summer of 2015 I … | Continue reading


@blog.persistent.info | 8 years ago

Multiple Windows in Hybrid React Desktop Apps

Quip’s desktop apps are hybrid apps: both the Windows and Mac apps are composed of a web React-based UI talking to our C++ Syncer library, along with some platform-specific glue code. While this allows us to support two additional platforms with a small team we knew that architec … | Continue reading


@blog.persistent.info | 8 years ago

WKWebView Communication Latency Revisited

Earlier this year I posted about WKWebView communication latency and how it’s not quite as good as UIWebView (when using WKScriptMessageHandler, the officially sanctioned mechanism). There have a been a few developments in this area, so an update seems warranted. Things appear to … | Continue reading


@blog.persistent.info | 8 years ago

Teaching the Closure Compiler About React

tl;dr: react-closure-compiler is a project that contains a custom Closure Compiler pass that understands React concepts like components, elements and mixins. It allows you to get type-aware checks within your components and compile React itself alongside your code with full minif … | Continue reading


@blog.persistent.info | 9 years ago

WKWebView Communication Latency

One of the many exciting things about the modern WebKit API is that it has an officially sanctioned communication mechanism for doing JavaScript-to-native communication. Hacks should no longer be necessary to get data back out of the WKWebView. It is a simple matter of registerin … | Continue reading


@blog.persistent.info | 9 years ago

RetroGit

tl;dr: RetroGit is a simple tool that sends you a daily (or weekly) digest of your GitHub commits from years past. Use it as a nostalgia trip or to remind you of TODOs that you never quite got around to cleaning up. Think of it as Timehop for your codebase. It's now been a bit mo … | Continue reading


@blog.persistent.info | 9 years ago

HTML Munging My Way To a React.js Conf Ticket

Like many others, I was excited to see that Facebook is putting on a conference for the React community. Tickets were being released in three waves, and so for the last three Fridays I have been trying to get one. The first Friday I did not even manage to see an order form. The n … | Continue reading


@blog.persistent.info | 9 years ago

How did Quip implement the spreadsheet feature?

I originally posted this on Quora, but I thought it would be good to archive it more permanently here. For some background on Quip's technology stack, see What technologies were used to build Quip? and How is Quip's web client implemented? The formula engine for spreadsheets is i … | Continue reading


@blog.persistent.info | 9 years ago