Latest Posts (20 found)

Not just development, distribution of software may change as well

Even if you are as averse to semver as I used to be in the course of my programming activity, you can still think of open source software distribution as something that used to follow a fixed number of steps. There is a branch where developments happen, and this branch oftentimes happens to be not really ready for reliable work. Then you freeze the developments for a certain amount of time (even if, in the meantime, the work can continue on some new unstable branch), fix bugs, ask people to test it. At some point the number of bug reports starts to drop, your team and your users start to believe there are no longer obvious critical flaws that are easy to discover in the next few weeks: then you call the branch 2.4 or whatever, and that's it. However now, with AI coding, it's not just development that has changed, but also the act itself of using software is affected: it is not just you that can ask an AI to do certain changes to the software, but also the recipient of the software itself. This is obvious in the domains where a piece of software has its main user base among programmers, but this is also true in general, as more and more technologically inclined users have AI access and coding agents. Because of this change, the idea of just having a stable branch with everything polished, and an unstable branch where everything is a work in progress, may no longer be the right way to do things. A code repository can also be a finished product, but could be even more useful if it is a template for how to do things around a given problem. Maybe the user will modify the code in order to specialize it for a specific set of requirements, hardware, specific problems to solve. Also, what is too unstable or unproven for the general public may be the right thing for another set of users. Take the example of Redis. For weeks now I have been iterating on a PR that provides strong memory savings for sorted sets. This work, if accepted, will hit every user of Redis, from people that don't have any idea about how Redis works, to users that maybe even contributed code in the course of years. From use cases that are trivial to use cases where a 50% memory saving on sorted sets could mean cutting a big slice of the cloud bill every year. For this last kind of user, having the final product (after all the testing and changes of design I'm doing to refine something that "just works", with the risk that maybe it will not even enter the code base) may be less interesting than having a 95%-ready branch since day zero. It is code they can test, adapt, iterate on, even specialize more for the problem at hand. Maybe DwarfStar is an even more telling example of how code repositories should be good examples more than finished products covering every piece of the features matrix. With local inference you have, in the specific case of DwarfStar, many kinds of GPUs, models, server mode, agent mode, CLI, SSD streaming, tensor and pipeline distributed execution. To test everything everywhere is complicated. Yet, once you have two solid examples of tensor parallel graph execution, a strong coding agent can infer how to implement the same thing for other backend/model pairs. Similarly, once you have an engine that supports two models well enough, a third can be implemented in an almost automatic way, using the existing code base as a guardrail for coding agents in order to guide the implementation. This does not mean that a project like DwarfStar should not work out of the box, but that it could focus on supporting very well a set of features that can be extrapolated to a larger amount of possible situations that the users can cover themselves. It also means another thing: that main and unstable are no longer enough. Many experimental branches could be an integral part of the project. For instance, yesterday the Laguna S.1 model was released. It looks interesting on paper, however: will it really be good enough? Will the new DeepSeek v4 Flash checkpoints make it not really relevant for DwarfStar? It is too early to say. However, to collectively form an idea, publishing a branch with this model implementation is a good middle ground: people will try it, will refine it with their coding agents, and the community can collectively form an idea about how merge-worthy it is. Moreover, today I noticed how, thanks to the rails formed by the corpus of the code inside DwarfStar, the implementation was written in about two hours by GPT 5.6 Sol automatically. Implementing DS4 and GLM5.2 cost me a lot of steering, reading the model card and the details of the implementation of the attention of those models. Now it just worked. GPT 5.6 is more powerful but it also found a lot of good examples inside the existing source code. Software today is more malleable than ever. In some way this means that it can be released in a more fluid way. Also, it means that the documentation itself should not be just good for humans, but also for coding agents to understand how to change the system. How this will evolve exactly, and what the right point of balance between the different dimensions of stability, usability, and features will be, is not clear to me, but I believe we developers need to keep our eyes open to see where all this is headed. Comments

0 views

OpenAI Hacks Hugging Face, What Happened, Alignment and Paper Clips

OpenAI accidentally hacked Hugging Face, but the takeaways are more encouraging than people realize.

0 views

LG to Ban Residential Proxies from Smart TV Apps

The home appliance giant LG Electronics USA said this week it plans to suspend any apps built for its smart TVs that turn one’s television into an always-on residential proxy node. The move comes less than a month after researchers found that more than 42 percent of games and other apps available for download on LG’s webOS store allow unknown third-parties to route their Internet traffic through a user’s TV. Proxy SDK prevalence among smart TV apps for LG (webOS) and Samsung (Tizen OS) televisions. Image: Spur.us. On July 2, we featured research by the security firm Spur  that examined the prevalence of residential proxy software development kits (SDKs) in smart TV apps. Spur found more than 42 percent of apps available for download on LG smart TVs include SDKs that turn one’s television in a proxy node indefinitely, and that more than a quarter of the apps made for Samsung’s Tizen operating system had similar residential proxy components. Responding to questions about Spur’s research, LG Senior Vice President John Taylor told KrebsOnSecurity the company was working with app developers to remove the residential proxy option from their apps on the webOS platform. Developers that fail to comply, he said, will find their apps suspended. “A residential proxy network is not an intended use for LG smart TVs, and LG Electronics is working with developers to remove the residential proxy option from their apps on the webOS platform,” Taylor said. “If this option is not removed, these apps will be suspended.” Taylor said LG is committed to keeping residential proxy networks out of its smart TV apps going forward, and that the company’s review of those apps is “well underway now.” “As part of our ongoing efforts to enhance platform quality and the user experience, LG will continue to strengthen our evaluation process for developer-submitted apps, including those that incorporate residential proxy SDKs,” Taylor wrote in an emailed statement. App makers looking for ways to monetize their creations can turn to residential proxy providers, which pay developers to include SDKs that turn the user’s device into a residential proxy node that is rented to paying customers. In the case of LG and Samsung smart TVs, Spur found residential proxy SDKs bundled with everything from simple games like Pac-Man to screensavers and file utilities. A Pac-Man smart TV app from Bright Data offers users the choice between viewing ads in the game or agreeing to allow their TV to serve as a residential proxy node. Image: Spur.us. Spur’s report found the residential proxy network Bright Data accounted for a majority of proxy SDKs across both Samsung and LG smart TVs. Bright Data did not respond to requests for comment. Bright Data and other proxy providers named in Spur’s report all say they follow rigorous know-your-customer processes to validate legitimate uses of their services, which is often heavily tied to content-scraping activities by said customers. The proxy companies also say they incorporate technological countermeasures to prevent proxy service customers from being able to interact with and control other devices on the proxy user’s local network . Spur argues the problem is not that residential proxy networks exist, but rather that they are being embedded at scale in devices that most consumers do not think of as computers and are not equipped to audit. “A one-time consent prompt buried in a TV app is not a substitute for meaningful transparency, ongoing control, and platform oversight,” Spur’s Trevor Sutter wrote. “The risk is amplified when consent comes from individuals within the household who use the device but shouldn’t give consent, such as minors.” LG’s announcement that it is culling residential proxy SDKs from its app store is welcome news, but the company recently came under fire for another questionable partnership: Pimping McAfee security products via software drivers included in its high-end LCD monitors. Earlier this week, the Youtube channel Gamers Nexus showed that certain LG LCD monitors will automatically install an app that promotes paid McAfee antivirus subscriptions, and that the app arrives through Windows Update without an approval prompt.

0 views
Unsung Yesterday

“Something seems to be going crucially wrong with the frame rate.”

Let’s Game It Out is a YouTube channel where Josh Knoles occasionally grabs a modern videogame and tries to play it in a particularly creative way – finding bugs, breaking things, doing an action more times than anyone thought possible. What makes it even more fun is that what’s tested often are early access , unfinished games. Here’s an example 27-minute video of a game called Parking Tycoon: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/something-seems-to-be-going-crucially-wrong-with-the-frame-rate/yt1-play.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/something-seems-to-be-going-crucially-wrong-with-the-frame-rate/yt1-play.1600w.avif" type="image/avif"> There are many more . I could tell you that occasionally putting one on teaches me something about bugs or lets me put myself in the mind of a very inventive user. Sure, occasionally, perhaps. But mostly these are just fun to watch. = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/something-seems-to-be-going-crucially-wrong-with-the-frame-rate/1.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/something-seems-to-be-going-crucially-wrong-with-the-frame-rate/1.1600w.avif" type="image/avif"> #bugs #games #humor #youtube

0 views
Martin Fowler Yesterday

Fragments: July 21

With this post, I’ll wrap up my notes from the second Future of Software Development Retreat . But before I do, I should note that the full Thoughtworks report on the retreat is now available . They have five headline findings: ❄                ❄ A session convened around the mismatch of views about using LLMs between engineers using it and the C-suite and boards that were calling for it. The concern is that boards are looking at promised productivity gains, and not concerned enough about the risks, particularly about security. This was illustrated by one tale of a company that used ML-trained software to optimize the replacement of air filters on their field equipment. They were pleased to see that they were able to change the air filters less frequently, saving them $50 million. But the problem was the ML models were trained on equipment used in the desert, while their equipment was used in the arctic. Air filters in the desert deal with dust, but in the arctic the thing to remove is mosquitoes. There’s an important difference here, mosquitoes rot, and enough decaying mosquitoes is a serious fire risk. Fires from such dead mosquitoes around infrequently replaced air filters cost the company $100 billion . Now such a tale could told of many situations without AI in the mix. Plenty of human situations have gone wrong when solutions are applied in a new context (which is why context is such a key word among pattern-writers). But the tale does remind us to be wary of an AI’s suggestions, and to always think of how to build sensors to provide rapid feedback. Engineers particularly worry about the risks when citizen developers start vibe coding . In many ways, of course, this isn’t new. I.T. folks often worry about how many important business decisions are based on spreadsheets, that are built with little control, testing, or assessment of data quality. Vibe-coding amplifies these concerns, so companies need a range of controls to guard against security breaches . Some folks have made a point of raising issues at board level, running threat modeling session with board members to introduce them to the risks. Vibe-coded applications need to be put in separate infrastructure, which deterministic controls over data access to tame the lethal trifecta . One company encouraged widespread vibe-coding from citizen developers but recoiled from the problems of the huge shadow IT that emerged - they are now looking to build a platform to help control this work without stifling the useful tools that were produced. Part of the problem here may be simple experience with LLMs. Many in management find LLMs do a decent job of preparing management reports. Or summarizing management reports prepared by other LLMs. Given this they naturally think LLMs must do a decent job of programming too. My anti-management self has to mention Kelsey Hightower’s observation: The less busy work you have the less appealing these Al tools are One possible antidote to this: get the legal department involved. They see LLMs doing a poor job, and appreciate the risks involved. ❄                ❄ Most folks I talk to, both at the retreat and outside, recognize we are in some form of bubble. Technological advances like this almost always come with economic bubbles, and in the future we will all look back at this, and shake our heads saying we knew there was so much froth. But while it’s easy to see that there is a bubble, it’s hard to see how long it will run or what will emerge after the pop. After all the dotcom bubble was clearly recognized as such… in 1995. We can happily point at those companies that failed (Webvan, pets.com) but need to then acknowledge those that survived (Amazon). Most of those at the retreat were old enough to have lived through the dotcom bubble and crash, but one such grey-hair pointed out an interesting difference. Back then we were excited about what the future would bring, and we saw lots of new things being built. There’s much less of that, this time around. Most people are wary of what the AI bubble is creating. Partly this may stem from the reality that followed the dotcom hope. Social media may be everywhere, but do we think it’s actually improved our lives that much, even if (especially if?) we use so much of it? We hear so much about the incredibly productive things we can do with agentic programming , but has anyone noticed a flood of wonderful applications built with it? Or have we noticed a significant improvement in common applications from the big AI boosters such as Google or Microsoft? This may be another factor in the board-vs-engineer divide. Most of what’s driving adoption of AI at the moment is cost-cutting, and it mostly the boards that get excited by cost-cutting. Perhaps the increasing concerns about token costs will temper the eagerness. ❄                ❄ Folks are finding LLMs helpful in operations: with a good event stream from observability tools, an agent finds anomalies much faster. One of the problems with citizen-developer apps, is that they often don’t provide good observability, since the citizen-developers don’t think to ask for it. The agents ability to look at the event stream does pose governance questions, as often such event streams contain a lot of sensitive information. Reinforcing what I’d heard in Utah, more people agreed that LLMs are valuable for operations folks to help them understand what the code does. Cross matching code and event traces helps them assist humans to find what happened when things go wrong. Agents are particularly handy with repeated incidents, as they can collate lots of information from different cases and present it to the human teams. Getting agents to auto-remediate moves us to the next level of capabilities and concerns. It’s vital that agents carefully document all their actions when they do fixes. We also need to ensure there is feedback to the development team so they can learn. Agents don’t learn, the best they can do is update the context. There was a sense that many people over-estimate the capability of agents to deal with incidents. Such people think of incident resolution as a simple, linear process. But it’s rarely that, instead there’s a lot of surprises and adaptation needed. Humans are good with that, but LLMs are not. One of the perils of agent-developed code is their habit of inserting features that were never asked for. One team spent three days trying to figure out such an unrequested feature, trying to figure out who had requested it and if anyone wanted to keep it. ❄                ❄                ❄                ❄                ❄ A group of law professors carried an interesting experiment to judge how well an LLM can provide short answers to student questions . They created a batch of forty questions in contract law and asked the professors, plus a couple of LLMs, to provide answers. To evaluate the LLM answers they showed professors pairs of answers - one human, one LLM - and asked them which response they would prefer to deliver to a student. Professors rated LLMs far higher than their peers (average win rate = 75.33%), with models performing similarly to the best instructor. LLM responses were also rarely flagged as harmful (3.53%, vs 12.06% for professors). This reminds me of the distinction I mentioned in a recent fragment between interactional and contributory expertise . ❄                ❄                ❄                ❄                ❄ A few days ago Unmesh Joshi published an article here about his experiences using DSLs to enable more reliable use of LLMs . Responses to this included a pointer to an article by Spender Nelson that related similar impressions . DSLs like this hit a lot of sweet spots for LLMs. You can make them extremely token efficient, and enforce hard security boundaries. You can translate high-level LLM intent into a ton of deterministic code, ensuring good behavior and guardrails at the (custom) compiler level. And Large Language Models are very good at learning and working with DSLs. Maybe this shouldn’t come as a surprise; they are language models after all. A small bit of documentation generally is enough to set them off and running, and reasonable error messages let them course-correct even when they go wrong. He describes a couple of examples from their use: a query language for data lakes that takes into account security and authorization issues, and a little expression language to make it easier to create safe SQL where clauses. One of the biggest barriers to using DSLs, particularly external DSLs , is building a parser and tooling. LLMs make this much easier. That said, my sense is that it’s the semantic model that underpins the DSL is what really matters, and the DSL is one projection of that model. LLMs may help us explore other ways to project that model in interesting ways. ❄                ❄                ❄                ❄                ❄ In recent weeks I’ve been noticing the stench of LLM-speak more and more. It’s not just the common tells, it’s a sense of LLM miasma that pervades the prose. I’ve noticed it’s increasingly eliciting a visceral reaction, after a couple of paragraphs I just want to dismiss the entire article out of hand. For some of these, it was necessary for me to hold my nose and wade through the whole text, but it was with an intellectual nausea which obscured the content, even increasing my desire to indulge in such an awful distraction as checking social media. I wonder - is this just me that’s reacting so negatively to LLM-speak? Or do other people have a reaction that leads them to toss aside any prose that sets off their LLM-alarm? One indicator that it’s not just me is this post from Jason Koebler that I highlighted a couple of months ago, where he observed how AI was breaking his brain : People think things that are fake are real, things that are real are fake. Much has been written about “AI psychosis,” the nonspecific, nonscientific diagnosis given to people who have lost themselves to AI. Less has been said about the cognitive load of what other people’s AI use is doing to the rest of us, and the insidious nature of having to navigate an internet and a world where lazy AI has infiltrated everything. Our brains are now performing untold numbers of calculations per day: Is this AI? Do I care if it’s AI? Why does this sound or look or read so weird? Does this person just write like this? Is this a person at all? A while ago, I was thinking that it was reasonable for folks who aren’t as committed to writing as I am to use an AI to help polish their prose. Now I’m turning to encouraging writers to reject it. That pervasive LLM-voice is just so common now, my sense is that it discredits the writing even before the reader has a chance to try to understand what is being said. I don’t think it’s good enough to ask the LLM to write a first draft and then tweak it. I’m not sure writers can edit the LLM-ness out of prose once it’s in there. I even worry about asking an LLM to suggest improvements, I think it’s just too easy to accept an LLM’s suggestions, and in the process trigger your readers’ LLM-antibodies. Of course like most problems, it’s also an opportunity. Those who can get a distinctive human voice will get more visibility and credibility. But the question remains of how we can coach people to let out their true personality into their writing. Academic and corporate writing both tended to stifle engaging prose, LLMs are good amplifiers, and they will amplify this stifling. This is an even greater challenge for those for whom English is their second language (or indeed for many of my colleagues, their third or fourth). It’s too easy for me to neglect to think about a difficulty that I’ve never been able to face. The most immediate advice I can give something I learned many years ago and shared last year - Say Your Writing . Once you’ve got a reasonable draft, read it out loud. By doing this you’ll find bits that don’t sound right, and need to fix. I always suggested this to help people get past sluggish prose, especially if they had spent too much time around academic or corporate writing. But now I think the need to Say Your Writing is even more important, in order to combat the insidious impact of AI. For most people, their speech patterns get closer to their real self, so verbalizing writing is the way to fight those forces that try to smooth away a writer’s individuality. Code generation is no longer the bottleneck — verification is. ‘Harness engineering’ is emerging as a distinct, ownable discipline. Organizations are colliding with a real apprenticeship crisis. The executive/engineer expectation gap is a bigger risk than any technical limitation. Legacy modernization is the clearest, most defensible near-term value pool.

0 views

A Fireside Chat with Cat and Thariq from the Claude Code team

Earlier this month I hosted a fireside chat session at the AI Engineer World's Fair with Cat Wu and Thariq Shihipar from Anthropic's Claude Code team. We talked about Claude Code, Claude Tag, Fable, coding agent security, evals, tool design, and how Anthropic use these tools themselves. The full video of the session is now available on YouTube . Below is an edited copy of the transcript, with extra links and my own bolded highlights. A few top-level notes if you don't want to watch the video or wade through the whole transcript: Simon: Claude Code came out in February of last year — it's under a year and a half old, and it was originally just a bullet point on the Claude Sonnet 3.7 launch . How has what you do on a day-to-day basis changed in the past year , now that we have these coding agents that actually work for us? Cat: I remember when we first came out with Claude Code and Sonnet 3.7, you would give it a task and you would have to closely monitor every single little thing it tried to do. I would read every permission prompt extremely carefully. I would frequently say no — no, no, no, did you check this file? Did you check that file? And now it's been incredible with every model generation. I feel like we've all gotten a chance to take a step back and delegate a lot more of the menial implementation to Claude . It's freed up a lot of our time to think about more creative work, like: what is the right experience that we should be providing to our users, now that we know Claude Code can implement a lot of it? And now with Fable it's a totally different step change improvement. We see for a lot of our use cases that you can actually one-shot a ton of features with Fable now . Thariq: I remember the first text I got about Claude Code. One of my best friends was like, "You need to go try Claude Code." It was about when Opus 4 came out, and I tried it and I was like, "Oh, shit. I need to work at Anthropic now." And that was Opus 4 — great model, but you were reading permission prompts. It's kind of crazy how much amnesia we have, where I'm like, oh, auto mode has always been here, right? I don't even remember pressing yes and allow. For me, the big thing I'm trying to push myself on is that we have to do higher quality work than we've ever done before . The outputs are incredibly high quality. I've been using it to edit videos a bunch , and I'm like, okay, it has to meet the very exacting demands of our brand team in a couple of hours or we just can't do it. That's how I'm trying to shift with Fable: the best work we've ever done, faster than we've ever done it before . Simon: What's a piece of conventional software engineering that was true a year ago that you don't think holds anymore in this new world? Cat: One of the biggest shifts we're seeing in the eng skill set: two years ago it was pretty typical for a product manager to go talk to a bunch of customers, align over the course of six months with cross-functional teams on some PRD, and write a thorough spec on exactly how we'll implement this before the first line of code gets written. Now things are completely turned the opposite way. For a lot of engineers, the push I would give to folks in the room is to develop more of your business sense and product sense on what it is we should build , because the timeline between having an idea and building it is so much shorter — it's down from six to twelve months to maybe even a week. That means all of us need to have better taste on what is worth building, what will actually inflect the businesses we're working on. So it's an increase in value on product taste and business sense , and a bit lower on execution in most product domains. Of course, for infra there's still a very heavy emphasis on making sure all the details are right. Thariq: For me, it's that rewrites are now good . Simon: The worst thing you could do is now actually fine! Thariq: Exactly. All the Mythical Man-Month stuff — never rewrite — I'm pro-rewriting now. If you have a good test suite — and I think the rewrite actually forces you to make sure you have a good test suite — but I think what people undercount is that a codebase is a spec, and maybe it's the only copy of the spec that you have , because no one knows every branching part of the codebase. You can take this as an artifact and distill it or create other versions of it. We rewrote Bun in Rust and it works great — it's live for me right now. Simon: You're not shipping Claude Code on Bun-in-Rust yet, right? Thariq: Internally we have. (Actually it looks like Anthropic started shipping Claude Code on Bun-in-Rust to everyone on June 17th .) Simon: The other big launch recently was Claude Tag — that's what, a week old now, at least for the rest of us. I understand it's being used at Anthropic by non-engineers a great deal. What kind of things are non-engineers doing with Claude Tag? Cat: Claude Tag is a Claude that lives in your team's collaboration tools. We launched it last week within Slack. The thing that's different about Claude Tag is it's multiplayer by default . Once you add Claude Tag to a Slack channel, you can chime in, your teammates can chime in, and you can collaborate together on the PR. The other big difference is that it's proactive instead of reactive. You can tell Claude Tag, "Hey, monitor every bug report in this channel, put up a PR to fix it, and tag the engineer who last touched this part of the codebase," and it'll do it for the lifetime of the channel without you having to manually tag it in. And the third big shift is that we've added team memory into this . If you tell Claude Tag your preferences in the channel, it'll remember them for every future post. If you always want it to debug outages but you don't want it to debug warnings, just tell it that in natural language in the channel and it'll remember it for you and everyone else on your team. Internally, we see Claude Tag as the evolution of Claude Code. We see this as a large shift in how we work internally. Claude Tag currently lands 65% of our product eng PRs. Simon: For all of Anthropic, or just for Claude Code? Cat: This is just for our product engineering team — our internal version of Claude Tag lands 65% of our product PRs right now . And this is a huge shift; this is more than 50% of our PRs. The way we see people split work between Claude Code and Claude Tag is: Claude Code is still the best place for your most complex tasks, when you're interactively iterating with the agent. But Claude Tag is great for having it work proactively on your behalf , so you no longer need to manually kick off Claude Code for all the bug reports that come up for features you're working on. Thariq: And for non-coding cases: for example, before this talk we asked Claude Tag, "Hey, when is Fable releasing?" We wanted to make sure we'd line it up with the announcement. Claude Tag would search our Slack and look at who's been saying what. As a search engine for your company, it's really valuable. It has all the context for your product, so you can ask it metrics-related questions — often when you're making decisions you want them informed by what the metrics say, so you hook it up to your event store. I've seen our marketing team do things like, "Hey, tell me about this feature." They're not programmers, but Claude is a programmer — it can clone the codebase and say, "This is the feature, this is what it looks like, this is a recording of me using the feature ." It enables a whole wide variety of things, and I think we're still early in figuring that out. Simon: One of the problems I've had with coding agents is that I get how to use them as an individual, but I'm not really clear on how to use them in a team environment. It sounds like Claude Tag is your current answer to that team collaborative layer for this stuff. Cat: Exactly. And a large percentage of our sessions are actually multiplayer right now. Maybe I say, "Hey, I think we should implement this new feature in Cowork," and I'll tag in Claude Tag to do a first pass at it. Then I'll tell Claude Tag, "Share a recording of your final implementation," and I'll tag in design to take a look. They'll nudge it, then pass it on to eng to take it to the finish line and get it out to prod. It's been this very fluid experience. We're still trying to iron out what the social dynamics are for steering the same session , but we've found that people just observe how others use it and follow those social norms — it's been pretty intuitive for us to integrate Claude Tag into our teams. Thariq: It's great for teaching people, and also for reducing slop, because the fact that everyone is seeing you use Claude together sort of levels up how you use Claude as well . This reminded me of how Midjourney solved the challenge of teaching people advanced image prompting by enforcing prompting in public in their Discord channels. Something I've found really hard myself is knowing when a feature is worth shipping now that the cost of actually building features has dropped so much. Simon: How do you deal with the hardest problem in all of engineering — prioritization? How do you decide which features are worth building and shipping when building a feature is so much more inexpensive now? Cat: This is the hard thing. There are a few ways we approach it. One is we dogfood our products every single day. Whenever there's something we want to be able to do in our products that we're not able to, instead of finding a different solution we fix our product so it can support that case. We have a very heavy dogfooding culture internally. Before we share our products with everyone in the world, we share them with everyone within Anthropic, and with some early customers who give us very honest feedback about it — the more brutal the better — and we iterate until people love it. We have an internal bar for the number of active users and the amount of retention a feature has to have before we share it with the world. Because this bar is very clear, every engineer knows what they're trying to hit. I think this also levels up our polish, because if the feature isn't polished, people will churn — and then we shouldn't ship that feature. Using internal user-retention to decide if a feature should ship makes a whole lot of sense to me. Simon: Do you have an example of a feature which surprised you? You rolled it out and the engagement was off the charts — something unlikely to be shipped that turned into a real product thing. Cat: I do have one. A lot of folks on our team love remote control . Remote control lets you use your mobile device, or Claude in the web browser, to connect to a local Claude Code session running in your CLI. I never have this need, because I just kick off the task directly on mobile and it runs in a cloud session without using my local environment — I think because I'm doing very easy coding tasks. It was something I didn't totally understand; I was like, hey, people should just set up remote dev environments. But in practice, once we rolled out remote control, so many people I talk to told me that what they do every night is plug their laptop into a power charger, open a bunch of remote control sessions, lock the screen, and then use their mobile phone from their couch to control Claude Code . So this has become a flow we're now leaning into that I didn't originally get — but now I do. One of the over-arching themes of the conference was review: how much attention to people spend to reviewing code written for them by coding agents. I was very keen to hear the Claude Code team's take on this! Simon: How does code review work? Does a human being review every line of production code that makes it into Claude Code? And if not, what are you doing — how do you keep the quality up? Thariq: It varies on the task a lot. For important areas we have code owners. The system prompt is an example where we have a code owner — you really need to get their approval. Simon: So the code owner is directly responsible for the quality of that area of the code. Thariq: That's right. Cat: And they need to approve any PR that touches it. Thariq: We have our code review GitHub bot review everything — that goes on every PR, and often it's doing the bulk of the review. Something I've seen on the team is that for more complex PRs you might make an artifact to explain the PR so that other people can then review. And we invest a lot into verification, CI/CD, things like that, to make sure that any time anything fails we have a test. We have a really robust environment where Claude can control Claude Code and test it. So there's a multi-pronged approach to code review. Cat: In general, we are trying to move to a world where humans don't need to be in the loop . For the most critical changes to the core of Claude Code, and the cores of other products, there is always a code owner and they do manually review all the changes. But increasingly, for the changes at the outer layers, we actually have Claude code review fully review those . That sounds pretty scary, but we've had a six-plus-month-long process to get here, and there are baby steps that you take to build up trust with code review . In the beginning we had human review for everything, and then increasingly we would say, okay, for code changes that touch these files, code review is catching 100% of the issues there — so we actually don't need a human manually reviewing those . And when we have incident review, we look at the PRs that caused the incident and say, okay, how do we update code review to catch that? — and we take those PRs and add them to an eval set to make sure our future changes to code review never regress that metric. Removing humans from the code review loop is a big step forward. It can sound scary, and it's not something you can do overnight, but it is something you can do through many months of investment in the infrastructure to give you the confidence that code review is catching everything you care about. So the key seems to be constantly iterating on the automated review systems themselves, in order to build trust in them over time. We got deep into evals - another hot topic throughout the wider conference. Simon: I know that Opus 4.8, if I ask it to build me a JSON endpoint that runs a SQL query and outputs JSON, is just going to get it right — that's not something I have to review closely. But then a new model comes along and I don't know how to build trust in Fable quickly, that it's not going to mess things up that Opus didn't. How does the new model affect your intuition for what it can do and what it can't do? Cat: The main reason we're building up this eval base over time is so that new models can be a drop-in replacement . When we have a new model, we run the whole eval set and make sure that, for example, Fable is strictly better than Opus 4.8 — and that gives us the confidence to drop it in. Simon: Are those model evals for Anthropic as a whole, or Claude Code team-specific? Cat: We have both. We have evals on our team, and we run code review across every repo within Anthropic, so we have evals for that. And for things like auto mode, we not only have evals across every user within Anthropic — we've also commissioned multiple external testers to red team it, to create environments with prompt injections and malicious inputs, and make sure that auto mode doesn't let any of those pass . Simon: I want to know if the system prompt improvement I made actually improved the product — that's the most basic form of product-specific eval, and I still don't have a great feel for how to do that. Is that something you're doing such that you have complete confidence that a tweak you've made to the system prompt results in better output? Cat: We don't have complete confidence, but we do a lot to make sure that we don't regress performance. The starting point is a suite of external evals that we trust, and we complement that with an even larger suite of internal evals that we trust. To start, we mainly optimize for capability : given a complete definition of a task and the full codebase, does Claude make the right decisions, fully fix the bugs, and pass all the tests? That's the starting point and the thing we optimize for, because it's most directly what users want. But there are a lot of behaviors that impact how users feel when they work with Claude Code. For example, people really don't like it when Claude Code says it's time to go to sleep. Or people really don't like it when it says, "Hey, I finished two out of five parts — do you want me to continue?" Yes, please continue. So we're building up a set of behavioral evals to catch these. And as we get user feedback — please be loud with us about your user feedback — we rank the priority issues and go down one by one and build evals for each of them. It's not 100% coverage, but it is a priority for us to increase the coverage. Simon: How much interaction is there between the Claude Code team and the teams at Anthropic who are training the models in the first place? Is that quite a close collaboration? Cat: Across Anthropic, we all work quite closely together. We meet often to talk about what we expect the next generation of models to be able to do. Our research team has also been amazing about showing this publicly — we often talk in our blog posts about how we're targeting ever-increasing longer-horizon work , and how we train Claude itself to be honest, harmless, and helpful. We also put a lot of effort into making sure it's aligned with your intent, even if your intent is expressed in a fuzzy way. Of course, try your best to be specific about what you want, so Claude has all the context — but even when you're not specific, we teach Claude to make good assumptions. It's been a productive partnership. So many useful prompting tips in this section! Simon: Thariq, you mentioned this morning that the system prompt for Claude Code has been reduced by 80% because of Claude Fable . Can you go into a little more detail? What kind of things have you been able to drop? Thariq: It wasn't just Fable — it was Opus 4.8 as well, and going forward, future models. We have different system prompts for different models now. One of the patterns we saw is that we were over-constraining Claude. The initial, maybe Opus 4-ish models wanted a lot of examples, and removing examples was extremely helpful , because it was just more creative than the examples we gave it. Simon: That's really interesting, because one of the top prompting tips I give people is: give it examples. If that's no longer true, that kind of breaks my prompting model a little bit. Thariq: Same here — I was surprised to hear that. I think now it's more about the shape of what you give it — the tools you give to Claude, your system prompt, things like that. The other thing we did is try to give it more context and fewer "do not do this" instructions, because that's a very strong impulse for Claude, and especially if it conflicts with user instructions later on, that can be extremely confusing to Claude — "I've got this skill that says this and the system prompt says this." So we try to have fewer hard constraints, more context, and fewer instructions overall . It's definitely a science — it took a bunch of evals to build. Cat: In general, when you're prompting these models, you should always think: are there edge cases to the instruction that I'm giving it? When we went back and reviewed all the instructions in the Claude Code system prompt, we found a few cases where yes, this statement is 90% true, but there's a real 10% of cases where it's not true . We didn't want to constrain the model, or confuse it into thinking it should always do this. One good example is verification. Everyone here wants Claude to verify its work, and we had some instructions in the prompt that said: if you make a front-end change, always verify. But there's a limit to it. If it's changing copy from one string to another string, and the user says "just make a quick fix and update the test," maybe you don't want to verify. So we've adjusted our wording from "always verify, verify, verify" to something like: most of the time when you're doing front-end work you can't fully understand the experience by hitting the backend endpoints, so when you make larger changes to the user experience, please run the app locally. And in fact, that instruction probably isn't even good either, because what is a large change? Maybe it should test small changes too. In general, whenever you give a prompt to the model, you should think about the ways in which it could be misinterpreted by a well-intentioned human , in order to better understand how the model might interpret it — and soften the prompt so that it's actually 100% accurate, because you're giving this prompt to the model 100% of the time. Simon: What's fascinating about that is you're relying on the model's judgment — and that's got to be an Opus/Fable-level thing. Models a year ago did not have the level of judgment necessary to decide whether they were going to test a change or not. But that does break down if you're building for a wide range of models and trying to run the cheaper models for cheaper tasks. Cat: We actually have a different system prompt per model now , for this very reason. It's only our most frontier models that have this 80% token decrease — the older models still have the full system prompt. Simon: Do you think Fable and Opus are smart enough to prompt Haiku with more details, because they understand that Haiku has less judgment, less taste? Cat: We haven't been able to eval it — we don't have any hard data to show it. Thariq: There's a tough thing with smaller models sometimes, because sometimes the larger models can be more token-efficient on a hard problem than the smaller models . So there's a bit of intuition to build there — sometimes you really just want frontier intelligence almost all the time. The Pareto curve shifts, and it's hard to find. Simon: A year ago I did not trust a model to write a prompt. Today the good models are very good at prompting — a lot of my prompts are written by models, which feels absurd but works really well. What helped me come to terms with that was thinking about subagents, which are entirely about a Claude model setting up a prompt for another Claude model. Thariq: Workflows are actually a really good example of this, because it's Claude not just prompting a single subagent, but prompting the orchestration of many subagents, and each one of them gets a very detailed prompt. It's almost a level above just spawning a subagent. I've also been using it on my personal machine, giving it the Gemini API and saying: here, generate images . It's way less lazy than I am at prompting an image model. It's just Claude prompting Claude all the way down. Cat: I think Claude also wrote the prompt for the workflow tool . Simon: I've read that prompt — it's a good prompt. That's actually a frustration I have with Anthropic generally: you publish the prompts for Claude Chat , but you don't include the tool prompts and the Claude Code prompts. I still have to run a proxy to intercept them. I would love it if the Claude Code prompts were deliberately published — they're the documentation. They're how you know what the tool can do and how it works. Cat: I'll write down that feature request. I'll have Claude Tag do it. Interesting to note that OpenAI's prompting best practices for GPT-5.6 includes similar advice for their latest models: Favor leaner prompts Removing repeated instructions and examples and simplifying tool descriptions can improve task performance and token efficiency. In a sample of internal coding-agent eval runs, configurations with leaner system prompts improved evaluation scores by roughly 10–15% while reducing total tokens by 41–66% and cost by 33–67%. Simon: Claude Code is basically a big bag of tools. What's your bar for introducing a new tool? How do you decide when it's worth doing that additional engineering at that level? Cat: Do you want to take it? You introduced one of the best tools we have. Thariq: My career peaked when I introduced the ask user question tool. It's really hard. Especially for some tools — ask user question is Claude's tool to ask you — so it's hard to eval, and sometimes it's more of a user preference thing. Back then we had fewer evals, so it was very dogfooding based — or "ant fooding," our ant version of that. But overall we've been trying to trend towards fewer tools . The last set of tools we introduced was the task tool, I think — and we try to give Claude more general versions to do things. I have a long-running fascination with file editing tools - they were the subject of the old Aider code editing leaderboard , and I've watched with interest as they've evolved in different coding agents from search-and-replace based to line-number-based to more complicated patterns. The Claude API docs describe a text editing tool that's recommended for building against the API, but Claude Code seems to use slightly different approaches here. Simon: One of the most interesting tools is the file editing tool — you can have file editing as a tool, or you can tell it to use sed and grep and do things that way. What's the latest evolution of your file editing tool? Thariq: We still have one, but for example we removed our grep and other search tools — glob tools — in favor of native bash. Like I said in my talk earlier, the models are kind of more of a biology than a physics , and tool design especially is quite hard. I'm not sure if Cat disagrees and thinks there's a science to the eval of it, but I think tool design is more of an art, maybe — or a biology. Cat: I largely agree, but in general as we introduce more tools, we try to keep the cardinality pretty low and make sure that every tool we add has a distinct function from every other tool, so that Claude can very easily distinguish when to call each . For file edit, the reason we have it is actually because we can render it. We show people when Claude makes a file change, and there's this nice dedicated UI that says: do you approve this edit to this file? The reason we had a dedicated file edit tool was so that we could deterministically know that Claude was making a file change, so we could show people this nice UI. A lot of new users onboarding still really like this experience, so we've kept it around. But for a lot of us who are on auto mode right now — hopefully you're not on YOLO mode — I don't think it actually matters, and we could probably just remove file edit and be totally fine. It's the prompt injection question! Who better than Anthropic employees to explain how Anthropic sees the risk of prompt injection attacks causing their Claude Code instances to run amok? It turns out they really trust their auto mode - and see that as the feature that enabled Claude Tag. Simon: Let's talk about safety and security. I am deeply aware of the risks of prompt injection, and there are so many bad things that can happen if somebody else tells my Claude Code what to do. I still mostly run Claude Code in YOLO mode and feel incredibly guilty about it. What's the advice within Anthropic for safely running Claude Code? Cat: Why not auto mode? Simon: I am starting to use auto mode, but I don't understand it enough to get how safe it is. As of maybe three weeks ago, I'm defaulting to auto mode. Cat: Broadly within Anthropic, almost every single person uses auto mode. It is the best way to do long-running work in Claude Code while being safe. We've done extensive bashing. We have thousands of evals. We've commissioned many red teamers to create adversarial environments in order to trick Claude Code into doing bad actions, and we've mitigated every single issue that they found. We're going to publish some evals in the coming weeks, but we've pretty much mitigated every attack. Simon: That is a big claim. Cat: We'll share the evals for it so folks can assess, but we've been extremely diligent about identifying all the ways in which Claude might mess up and then updating auto mode to counter it. It doesn't catch 100% of things — that would be way too strong a claim. But for the main categories of risks that we're concerned about, like prompt injection and data exfiltration, the risks are far lower than the average human reviewer . I am very much looking forward to learning more about their evals and approach to verifying auto mode. Thariq: A little on how auto mode works — it's useful to build this mental model. Whenever Claude is doing a turn, or a bash call, there's a Sonnet classifier that is judging the tool call and also the context of the conversation — your instruction. There are some things around permissions that are dependent on your request: you don't want to give git push permissions all the time, but if you say "push this to GitHub," you want it to do it — and if you say "don't push," you want it to deny it. Auto mode will do that. That particular thing happens to me a lot, where Claude tried to do something because it's very helpful and proactive, and auto mode saw "don't do this" and surfaced it. So it's good at the dynamic permissions that you yourself give inside the prompt, which I think is really important. It also works well with our sandboxing infrastructure , because sandboxing is one of those things where there are so many different edge cases that it's hard for us to deterministically follow them. We have a sandbox, and when something needs to escape the sandbox — like a network request — auto mode can look at that request and ask: does this make sense? — and allow it. Simon: I hadn't realized auto mode is interacting with the networking sandbox as well. Cat: It interacts with any permission prompt the user would otherwise see. Simon: How old is auto mode? As a feature I had access to, it's only a couple of months old, right? (It was first made available to the public on March 24th .) Cat: We've been using it within Anthropic since January , so we've been hardening it for quite a while. Anthropic is extremely focused on safety and security, and we've been working broadly across our alignment and safeguards teams to enable the rollout internally, build out these evals, and make auto mode even more robust before sharing it with the world. Thariq: This is also the reason Claude Tag is so good — Claude Tag uses auto mode . I've heard a lot of build-versus-buy questions about a Slackbot, and I'm like: please, you probably shouldn't build your own AI Slackbot. There are so many attack vectors. You have a feedback channel that users can post feedback into, and now your bot is reading it. The work we've put in with auto mode — and we have a general Swiss cheese defense for security; we also RL against this stuff — I think this is really what makes Claude Tag work . It works seamlessly with your permissions, and you don't want to be prompt injected in your Slack. Simon: Are there any more security things in the pipeline that go beyond auto mode? Thariq: I think we're very secure. With Claude Tag you can provision your own credentials for Claude , so it doesn't need to act on your behalf — you can have Claude as an identity, and that also makes it easier to audit and inspect what Claude is doing. Simon: Because Claude Tag is influenced by anyone who can talk to it — it's got a much wider pool of people telling it what to do. Thariq: That's right. And of course we have probes as well with Fable, which is a downstream effect of our safety and research work. I think this is the moment where you see Anthropic being an AI safety company really paying off: we really want Claude to be able to run in an aligned way over long periods of time , and auto mode has to be basically flawless for this to work — it's all downstream of our being an AI safety company. Cat: We also launched trusted devices for the remote control users out there who want to be safer. And for all of our remote environments, we support credential injection . If you want Claude Code to be able to access Datadog, but you don't want Claude Code itself to hold the Datadog credential, you can set up our identity and credential management system so that the Datadog credentials are only usable by the agent but not accessible by the agent — we insert them on the fly when the agent tries to make a Datadog request. I really like that credential injection pattern, where Claude Code can access an API via a proxy and that proxy both audits the request and injects the relevant API key - so Claude can access authenticated endpoints without having access to the API credentials itself. Thariq talked about a sense of grief brought on by Fable-class models in his keynote in the morning, and we dived further into that as part of our conversation. I've been calling this Deep Blue . Simon: Let's talk a little bit about the human element. A lot of people are feeling a sense of loss now that so much of what they considered to be their role in building software is being subsumed by the models. How do you think about that? How has the past year and a half changed the way you think about your own craft and the value that you add? Thariq: Cat and Boris are such good reminders that you have to be more ambitious. They're always like: we're growing so fast, we have to be on the edge, we have to do the best work we can. That's a constant reminder for me — any time I'm slow on something, I'm like, okay, can I do it faster? Can I be more ambitious here? And oftentimes the answer is Claude, because Claude is getting better as you go — the last time I tried this, it was with the previous model. On your point about loss: I think this is real. If you're only trying to do the same work you were doing before LLMs, and now it's a prompt, it is, I think, kind of a sad feeling. And the way you offset that is by being more ambitious. I think Jared is such a good example — he hand-wrote all of the Zig code in his Oakland apartment in about a year, barely left his house, and had so much fun doing that. Now I see him rewrite all of Bun into Rust and he's having so much fun doing that — it's so much more ambitious, and that's how he offsets it. Generally it's asking how do I do the bigger thing and do more — I think success is fun . It's changing your ambition. "The way you offset that is by being more ambitious" neatly captures where I've landed on this issue myself as well. Simon: And Cat, what does that look like from a product management perspective? Cat: I feel like the product role just changes every single month. All the PMs on our team are this mix of engineer, designer, PM — most of them actually used to be full-time engineers. For us it really means plugging in whenever there's any kind of gap . If we have an idea and we didn't inspire any engineer to go build it, then we should just build it, put it into a notebook, and inspire people to take it to production. If the designs look a little off, let's take a page that's similar, do a first-pass design, and tag in someone who's very detail-oriented to fill in the gaps . Or if we notice that our team and product adoption is bigger within the company, and more people need to know what's coming down the pipe for Claude Code, Claude Tag, and Cowork — let's automate figuring out our whole launch calendar, let's automate getting those status updates asynchronously so we're not bugging people, and make sure our updates in our internal announce channels are fully detailed and to the point. For us it's very much understanding what the gap is right now between a great idea and getting something to our customers , and how do we automate it as much as possible . This reflects something I've noticed: when you can produce code so much faster, time spent blocked awaiting a decision from someone else becomes a much more notable bottleneck. Engineers who can make product decisions can move a whole lot faster, and the cost of getting one of those decisions wrong is much less prohibitive. Simon: What's a moment when Claude has surprised you? When the model did something you didn't think it would be able to do? Thariq: I've posted a lot about Claude video editing, but most recently I gave a talk at the ACM Agentic conference, and I asked, "Hey guys, do you have the edited video? I'd love to post it and share it with my comms team." They said, "Oh, it's taking so long." So I asked for the raw files. They sent me the video of me talking on stage, the video of the deck, and the audio file, and said, "Good luck." I gave this to Claude, along with my HTML deck, and said, " Hey, can you just edit this together? " And what it does is honestly incredible — I'm ready to ship it. It transcribes the entire video. It notices that sometimes the video of my deck is a little weird — there's a popup of an auto-update in the middle — and it goes, " Oh, I probably shouldn't use the video of your deck. What I'm going to do is slice it up, figure out which slide you're on, and use the HTML source instead. " So it displays the HTML source. Then it's got video of me, but I'm only taking up a small part of the stage, so it's cropping dynamically to where I am on the stage — and I'm pacing, so it's tracking me as I pace. And it's transcribing what I'm saying. Simon: This was Fable, right? Thariq: This was Fable, yeah. It was a good prompt, but it was a one-shot prompt. Then I asked it to add some interesting animations and graphics, and I was just blown away. It does ffmpeg, it does Remotion. Here's Thariq's video on how he used Fable to edit Fable's own launch video , and here's that launch video . I'm embarrased to admit that I've been finding it quite hard to come up with tasks that frontier models like Fable 5 and GPT-5.6 are unable to accomplish. Cat still doesn't rate its UX design skills: Simon: What can't it do? What are the things where you're still disappointed — where you're waiting for Claude Fable 6 to figure it out for you? Cat: I want it to have better design and UX taste. It's now at the point where if I write out a prompt with a detailed spec of how I want a feature to behave, it will usually behave that way. But the paddings might be off, or the interface just isn't delightful yet. It leans on existing best practices for how apps are designed, but for frontier AI products, there are so many new interaction experiences that we have yet to design . Simon: There's an Opus aesthetic — you can look at something and go, "Yeah, that was designed by Opus." It'd be good if we could move beyond that. Cat: Yeah. I'm very excited for future models to hopefully be interaction design thought partners . Thariq: What can't it do? I would love to see it interact more with the real world. Can it solve science? Can it orchestrate the experiments? There's some amount of coding that goes into that, but there's also this other taste of the broader world that it needs. I figured this would make a great closing question: Simon: Which parts of Anthropic's company culture do you think uniquely help Anthropic be productive with these tools, that other companies should steal? What are the cultural hacks people should be adopting from you? Cat: I'll share one for Claude Tag. Claude Tag works best when you have it in a public channel, and when most of your channels are public. Claude Tag is able to search across all public channels to get as much context as possible to give you the highest-accuracy answer — and it's only able to do this if it has access to everything . Thariq: I mentioned this in my keynote, but it's so important to me I want to re-emphasize it. The co-founders say we don't negotiate against ourselves , and I think this is really important. You can imagine trade-offs in your head and talk yourself out of doing something ambitious — or you can just try to do the ambitious thing. We're so often asking: what if we just did it? Is this a real trade-off or not? And if so, why — where's the proof that it's a real trade-off, and not just something that sounds reasonable? Make the trade-offs show themselves to you. Be as ambitious as you can. I couldn't resist throwing in this one as well. Simon: What's one of your favorite absurd things that you've built with Claude, just because you could build it? Thariq: I'm working on a 2D Street Fighter fighting game with me as a character — and my friends as well. It uses Claude Code to prompt Gemini — and honestly the Seedance model is pretty good — to make video animations. It works great; it's so good at prompting, and it can verify the frames to check whether an animation was good. Simon: Is this Street Fighter 2-level 2D sprites you're generating? Thariq: Yeah, exactly — 2D sprites. The animation looks amazing. And it can also figure out hitboxes — it can be like, "Oh, your fist is here, I'll draw the JSON hitbox." It's incredible. Cat: Mine is much more simple. I'm a big rock climber and a lot of my friends climb, so we have this little app we built with Claude Code where we log all the projects we're working on. We also go outdoors together a lot, so we have Claude do all this research with workflows. Workflows is amazing — we brand it as a coding tool, but it's amazing for doing deep research for travel. I also plan our team offsites, and it's good at finding venues that can fit all of us. I use workflows to research all the climbing destinations we might want to go to, and what has direct flights from where all of us are located. It goes to Mountain Project and finds all the climbs at our grade level. It finds the Airbnb. And I don't like hiking, so I care a lot about it having a very short approach — very short walking distance from where the car parks to where the rock actually is — and it filters for this. With existing apps I have to manually click through Mountain Project, but with this I just put in all of our preferences and it's a custom app for us. Simon: So you're basically vibe coding Jira for mountain climbing. Cat: Exactly. We had a few minutes at the end for questions from the audience. Audience: Do you have any near-term plans to build more eval tools for us to build eval datasets, and more observability tools to monitor the performance of agents and workflows? Cat: We've considered building eval tools, but I think the limiting factor actually tends to be that it takes a long time for customers to build really high-quality evals . So I think the tooling is less of the constraint, and more the skill set of how you build a great eval. That's an area where we're excited to both invest internally and hopefully share some best practices externally. Audience (Sai): I'm interested in the memory and the multiplayer. How is memory being designed today? I assume it's around files. And second, have you thought about an orthogonal direction where you would actually need a data store for these memories, instead of files, to scale it better? Thariq: Right now for Claude Tag the memory is channel-specific. Every Claude in that channel has a shared memory, and the instances have a session — but the session can contribute back to main memory. We do a lot of memory research, and it can be kind of unintuitive what the right way to do memory is. We're always running memory experiments. How it works right now in Claude Tag is a markdown file per channel. You are only seeing the long-form articles from my blog. Subscribe to /atom/everything/ to get all of my posts, or take a look at my other subscription options . Claude Tag (Claude's new collaborative Slack integration) now lands 65% of the product engineering PRs for the Claude Code team. Claude Code ships features to Anthropic employees first, and only ships the features that demonstrate user retention with that cohort Critical changes to Claude Code are still reviewed manually, but the team increasingly relies on automated code review for the "outer layers" of the product. Adding examples to a system prompt is no longer best practice for models like Fable 5 or even Opus 4.8. The Claude Code system prompt recently reduced in size by 80% . Likewise, lists of " don't do X and don't do Y " can reduce the quality of results from the latest models. Dogfooding inside Anthropic is called " ant fooding ". Anthropic really believe in their auto mode , and see that as an enabling technology for Claude Tag. Thariq advises offsetting coding-agent-induced Deep Blue by " being more ambitious " with the work you take on. Fable is competent at editing video , and Thariq used it to edit its own launch video. Anthropic's culture of working (internally) in public is key to their success, as demonstrated by the way they use Claude Tag in their public Slack Channels.

0 views
James Stanley Yesterday

Should you wash your solar panels?

I have a small solar farm and the panels have got visibly dusty. Is cleaning them worthwhile? How much difference does it make? Let's find out. I know that my panels have not been cleaned in the last year. I expect they also weren't cleaned in the year prior to that (why would you clean them when you're about to sell the house?). But beyond that I don't know when they were last cleaned. The short answer is that I think I got a 2%-5% increase in power output from my solar farm due to cleaning the panels, which will work out to about £60-£150/yr, decaying to 0 over the course of a few years. So, probably just about worthwhile. Methodology There are 16 panels in total, connected up to the inverter as 2 banks of 8 panels each. The inverter reports the power output from each bank individually, so the plan is to take a bunch of readings before starting, then wash all of the panels in one bank, taking readings in between and at the end. Our hypothesis is that cleaning the panels will increase power output. We can test whether washing the panels has made any difference by looking at the ratio of power output from the 2 banks. If we just looked at raw power output then it would be confounded by changing cloud cover, sun angle, etc. There is still the fact that the 2 banks of panels are physically separate and plausibly one bank is better positioned for sun 45 minutes later than the other. Ideally I would have been measuring the ratio of power output for several days prior to see how it varies throughout the day. This is how the first row of panels looks after I've washed 3 of them, you can see the furthest one is noticeably grubbier: So they were "visibly dusty", but not massively dirty . If your panels are dirtier than mine were, then your benefit from cleaning them will be greater than mine was. My results for cleaning one bank of panels are shown in this chart: We see that the initial power ratio is very stable before the panels are washed. We then step up to having washed "half" a panel (I initially tried to wash them with window cleaner and a paper towel, but this was ineffective so I then walked away to get a bucket of soapy water and a cloth, and then took a reading which I labelled as 50% washed). For some reason the power ratio drops significantly when the first panel is washed, I'm unsure why. And then the power ratio increases as more panels are washed as we'd expect. But once all the panels are washed, the power ratio drops off again while nothing changes. I am unsure whether this is because as the surface water evaporates off the panels get slightly opaque again? Like the "frosted glass effect", where you can see through frosted glass when it is wet but it gets opaque again when dry. Maybe beyond cleaning the panels I ought to be polishing them? Anyway it looks like cleaning the panels was about a 2%-5% improvement, depending on what you think is going on at the end. I got a bit of a tingle when I was cleaning one of the panels. At first I thought I was getting an electric shock from the wet panel, but I inspected my finger and found a tiny thistle splinter in it. After I removed the splinter it seemed fine. But a bit later I got another tingle from another panel! There definitely wasn't a splinter in my finger any more, but the tingle was in the same place. I think the tingle actually was coming from the electricity, but I was only able to feel it at the point where the thistle had already pierced the skin. ChatGPT convinced me that there could just be a tiny "capacitive leakage" from an "inverter with no transformer", so I'm not going to worry about it. But if I clean the panels again I will wait until dark lol. The next question is should I be upgrading the solar farm? I think mine was installed about 15 years ago, and generates (at peak output) 3.7 kW from 16 panels. Correct me if I'm wrong on any of this: Replacing the panels with more modern ones would increase the power output by about 60%, at a cost of about £5000, which would pay for itself in about 3 years, which seems like a no-brainer. However, due to the fact that my solar farm was installed so long ago, it benefits from a feed-in tariff , which means that not only do I get paid an absurdly high rate, but it is paid also based on the electricity I generate rather than what I export . If I increase the power output of the system then the additional capacity will not be eligible for the feed-in tariff and will revert to present-day prevailing tariff which is about 4x worse before you even consider that I currently get to use electricity and still get paid for generating it . This is the yin and yang of market-distorting incentives. Today's incentive to install solar becomes tomorrow's disincentive to upgrading it.

0 views
Stratechery Yesterday

Netflix Earnings, Is Netflix Washed?, Additional Notes

Netflix's earnings were fine, and befitting a mature company whose most exciting days are likely behind them.

0 views
Farid Zakaria Yesterday

Linux kernel will support $ORIGIN, sort of

For some reason, during TacoSprint 2026 I decided to see if we could tackle relocatable binaries in Nix. I enjoy these lofty goals to push Nix and the surrounding ecosystem forward. I am bold if not stupid . I left the last earlier post with one potential idea of how to get there: We could patch the Linux kernel so that $ORIGIN is supported in PT_INTERP and the shebang. I waded through the complexity of sending patches over email (turns out I actually enjoy this workflow!), and sent a proposal to the Linux kernel mailing list. My first attempt here proposed simply adding direct support for in the Virtual File System (VFS) subsystem. I waited nervously. I was expecting the result from what I had come to read about online; someone non-politely telling me to F$#CK OFF because there is something I missed, misunderstood or did not consider. 🤬 The result was completely different. 😲 Christian Brauner , the maintainer for VFS responded to me in good faith, asking for the rationale for the change and eventually proposing some ways in which such a support could make it into the subsystem. Note It definitely helped having someone like John Ericson chime in and advocate why having a non-fixed interpreter ( ) is useful to Nix and other use-cases (i.e. Buck & Bazel). He offered that potentially we could leverage eBPF as a programmable way to select an interpreter through binfmt_misc . I wanted to merely allow but a programmable selection could let us do anything! The idea must have really intrigued him because soon-after, on his vacation , Christian offered the first draft of such a solution. We went back and forth a little over the mailing list and the end result is a patch series that will make its way into branch in the near future. If you don’t know what eBPF is or , WTF did we just collaborate on? Let’s take a look! I won’t do eBPF justice, and there are plenty of articles online about it as it’s quite in-vogue at the moment. tl;dr; You can write programs in a C subset that gets compiled to an instruction set whose virtual machine is running within the kernel . Shouldn’t the kernel be super fast? Yes, the programs are jitted to their native CPU architecture and the programs have a fixed-time slice. Isn’t this some crazy vulnerability for the kernel? Before any code is loaded it is “verified” to be safe. Checkout this guide for more info. We can now support with a relatively simple eBPF program: Once the above program is loaded and registered into the kernel, we then ask the subsystem to trigger it. Checkout this thread if you want to see the complete example. What does that mean? It means that every binary now triggers the function above, in this case any file, but it could be executables with a new segment like , and the kernel will ask to determine the interpreter to use dynamically. Our special BPF program has support for 💥 What else could you do? Well we can now even completely replace the traditional QEMU registration script with a BPF program now like this one . What else can we do? Since we can now programmatically select our interpreter based on anything in the file, we can do quite a lot. I’m keen to hear your suggestions and ideas 💡. Some of the smaller items are that we can even support in the shebangs ( ) very easily as seen here : we simply look at the first 256 bytes of the file and look for to trigger. One downside or side-effect of the traditional hand-off was that the way in which the desired final binary was invoked was non-transparent . The registered interpreter becomes the process. It owns the entire process identity, and the binary you actually asked to run gets demoted to an argument. For or that’s acceptable as they are emulators but for a per-binary BPF loader that might pick a traditional it does not make much sense. This leaks in a few painful ways but the simplest are : Christian sent a large patch series for this as well. His latest patch series adds two new dispatch modes that close the gap from opposite ends and covers a few other gotchas that these modes can fix. The loader substitition is the one I’m most excited about for Nix. With the flag, the kernel executes the matched binary natively as the main image, and merely substitutes the registered interpreter for the loader named in the binary’s . stops being a hand-off and becomes a plain override. There’s no contract and no identity to reconstruct, so a stock dynamic loader works unchanged . Where does this leaves us? I’ll be tracking the Linux kernel releases and, once this lands in and ships in a tagged release, I plan to upstream a NixOS module that registers the support at boot. 🎉 The plan is to gate it on a new segment rather than matching every file. That keeps things backwards compatible : the BPF handler only kicks in for binaries that explicitly opt-in by carrying the new segment. This means Nix produced binaries continue to work without the BFP handler but those that have it may elevate themselves to relocatable status . A ship in harbor is safe, but that is not what ships are built for. — John A. Shedd and show the interpreter invocation, not what you executed. names the interpreter. Relocatable programs commonly locate themselves through , and instead they find the dynamic linker. 😩

0 views
Julia Evans Yesterday

Some more things about Django I've been enjoying

Hello! I’m on a funny journey right now where I’m trying to learn how to make websites in a sort of 2010 style, where I have an SQL database and render some HTML on the backend. It’s kind of an interesting journey because it doesn’t necessarily feel “easy” to me to make websites in this way: I never learned how to do it in the 2000s or 2010s, and there’s a lot I need to learn. So here are some Django features that make building this kind of site feel more achievable than when I was trying and failing to use Go’s standard library or Flask. And I’ll talk about a couple of issues with Django I’ve run into. Previously the toolkit I felt confident with for making websites was: I really liked this frontend-heavy approach for these super simple applications but when I started thinking about making something with a lot of different pages (instead of literally just one page), I didn’t feel so excited about the options I saw that involved a lot of frontend code. So I figured I’d try the backend. Writing a backend-focused site that uses as little JS as possible feels the same to me in a way as writing a single-page JS website that does as little on the backend as possible, even though they might seem like opposites. In both cases I’m just trying to keep as much of the logic as possible in one place. Now for some thoughts about Django! I learned that I can define a “query set” class in Django with a bunch of methods with different statements I might want to use while constructing a query: Here’s how I use it in my view code once I’ve defined what all the methods mean: and here’s how I define the methods: The syntax for defining the filters isn’t my favourite, but I spend most of my time just using the methods, and it feels super readable and nice to use, and it makes me want to look into other query builder libraries in the future. In the past I thought “I know SQL, who needs a query builder?”, but this kind of structure does make it really nice to read. I found an example of someone who wrote their own small query builder in Python that I want to read later to think about whether I would enjoy using a more minimal version of this. There are a bunch of little quality of life filters available in Django templates that are super useful for generating HTML. The ones I’ve used so far are: These are all small things individually but I feel like it makes a big difference somehow to just have them available. I think my favourite template filter is : in this site sometimes we use filters like to decide what’s displayed. that will make a link to the same query string with one change, like this to link to the previous date: Or to remove the parameter: I still really love Django’s automatic database system. It’s amazing to be able to just edit a model to add a new field or whatever, and then Django automatically generates the migration. So far we have done 19 database migrations and I think there will probably be more! It makes a huge difference for me to be able to just easily change the database as my understanding of the problem changes. Django’s documentation sometimes offers the option of using class-based views and inheritance to organize the code in your views. For example I have four views that share a lot of code, and I could use inheritance to manage that by defining some kind of parent class and then having my other views inherit from it. I tried it out and I did not enjoy the experience of using inheritance to share code between views. I switched to using functions instead, sort of how this post advocates, and that was a lot more straightforward. I’ve never had a good experience using inheritance in Python and I don’t think I’ll try to use it again. But I don’t mind using inheritance to use the interfaces Django itself provides: for example if I want to define a query set I need to write something like . I don’t think too hard about it and it seems to work. (as a meta comment: I’ve been working on talking about my programming opinions by just saying “THING does not feel good to me, I prefer OTHER THING instead”. That post I linked to says that function-based views are the “right way”. I’m not very invested in whether it’s “right”, but it’s validating to know that other people feel similarly to me about inheritance) At some point the LLM scrapers discovered our site, and started sending us maybe 10 requests per second. I blocked them which is working for now, but it made me think about what the site’s capacity is. I’m used to writing Go backends where the performance situation is pretty straightforward (usually everything is just fast enough), and a Django site is very different. Some light load testing (with ( ) shows that right now we can serve about 2-3 requests per second (on a ~$10/month VM). It’s tempting for me to go down a rabbit hole where I do a bunch of profiling to figure out what’s slow and try to make it faster (there’s py-spy for that, and py-spy is great and super easy to use, and profiling is fun!) But I really don’t understand what I should expect in terms of performance from a Django site and how I should be thinking about at a higher level. Some things I haven’t figured out yet: I think one thing I’m learning about Django is that because it’s a Framework (tm), it’s easy to accidentally misconfigure it. For example, when I was thinking about why my site was slow just now, I read the django performance docs and I noticed a comment saying: Enabling the cached template loader often improves performance drastically, as it avoids compiling each template every time it needs to be rendered. When I’d done CPU profiling I’d noticed that it was spending a lot of time rendering templates! Maybe this could help me! Clicking through the link, I saw that the cached template loader was supposed to be on by default, but I’d turned it off by accident while trying to do something else. I think this “I turned off the cached template loader by default” things is an example of how I still find the django settings file to be pretty confusing and difficult. I guess I should just be careful when I go in there. After turning on template caching, it seems like the site can now pretty easily handle 12 requests per second or so without using all of the CPU. I have not carefully benchmarked the before and after but it seems like it’s made a pretty big difference. One thing that’s been surprising to me about Django performance is that I’ve always heard the advice “if you have a performance problem, check your database queries! Maybe add an index!”. But I’ve been running into a variety of performance issues (like this template caching thing) that are not because of slow queries, so instead it’s been more useful for me so far to start by running a CPU profile. And since I’m using SQLite, any slow database query problem will show up on the CPU profile anyway. Anyway I don’t want to get too far into site performance. Like I said it’s easy for me to get interested in profiling, but actually I know a lot about profiling and it’s not the most important thing for me to learn about. I might say more about what I’m enjoying (or having a hard time with!) about Django later. Trying to write some shorter blog posts recently. static site generators (like for this blog) static sites that do some fun stuff with Javascript (like this sql playground ) simple Vue.js single page apps with either a Lambda as a backend or a Go backend (like mess with dns ) translating plain text URLs into links, or line breaks into ( ) formatting dates ( ) , which takes a Python dictionary and automatically converts it to JSON and inserts it into the HTML as a tag in a safe way If I have a site that’s going to be getting occasional bursts of traffic, do I want to be able to scale up? Do I want to design the site so that more things can be cached? (and do I really have to? caches are so annoying to get right!) The django performance docs say that Jinja is faster for templating, do I want to think about switching templating systems? Those docs also say “{% block %} is faster than using {% include %}”, I wonder if it’s a big difference and if so why

0 views
Corrode Yesterday

Hardening Rust Code For Production

We talked about patterns for defensive programming in Rust before, in which implicit invariants that aren’t enforced by the compiler lead to utter misery. But being careful isn’t enough! Even valid code can fail at runtime in ways that are hard to predict and control. That’s what we’re covering next. This article is for you if you want to… What happens when a Rust program panics? There is no single correct answer because is not a “single behavior.” For starters, there’s a difference between unwind and abort. invokes a closure, which captures the cause of an unwinding panic. But the Rustonomicon has the following to say about unwinding panics: We would encourage you to only do this sparingly . In particular, Rust’s current unwinding implementation is heavily optimized for the “doesn’t unwind” case. If a program doesn’t unwind, there should be no runtime cost for the program being ready to unwind. The alternative to unwinding is aborting the entire process. That does what it says on the tin: the program immediately terminates without unwinding the stack or running destructors. Halt and catch fire. Weirdly enough, that’s often the safer choice, especially when dealing with FFI boundaries or performance-critical code. That’s because unwinding across FFI boundaries is undefined behavior, and unwinding can be expensive in performance-sensitive code. To enable aborting on panic, add the following to your : And even if you did not explicitly configure this, catastrophic panics like stack overflows and out-of-memory errors always abort the process . That’s because unwinding in these situations is unsafe and can lead to undefined behavior. In practice, this shows up in two places: These failures are fundamentally different from ordinary panics in that they cannot be caught or recovered from. To handle them gracefully, you need to know exactly how and where your program will run, and design accordingly. For example, in the case of , avoid unbounded user input that could lead to excessive allocations. Another difference is between thread-level failures and process-level crashes. A common misunderstanding is that terminates the entire program, but in a multi-threaded application, that is not necessarily the case. For example, a background worker thread can panic while the main thread continues running. What sounds like a benefit can leave the system in a partially degraded state. This distinction becomes especially important in long-running systems (servers, workers, async runtimes, …). A panic in a request-handling thread might only abort that one request, while the rest of the service remains available. Here’s a small example using scoped threads ( Playground ): The interesting part of the output is this: Request 2 panics, but requests 1 and 3 still finish. The panic belongs to the worker thread. The main thread gets notified on but keeps running. 1 Whether this is acceptable depends on the system’s invariants. If a panic indicates a violated assumption confined to a small scope, like a single request, letting the process continue may be reasonable. But if it signals a global invariant violation, continuing execution can be outright dangerous. Panic behavior is part of your system’s failure model . Treating all panics as equivalent hides important distinctions and leads to fragile assumptions. Be explicit about whether a failure may take down a single task, a single thread, or the entire process. Never panic in an uncontrolled manner. If you maintain a library, you have less control over where your code runs and what a panic can take down. Consider enabling stricter Clippy lints such as and to catch common panic sources before they become part of your public API. Those lints can be noisy in applications, but they are often useful when panic freedom matters more than convenience. Now that you understand how panics work, let’s talk about operational hardening. When things go wrong, you want to know about it. But by default, Rust panics just print to and disappear into the void. In production systems, that’s not so great. You might prefer crash reporting or centralized failure handling, and that’s where panic hooks come in. A panic hook is a function that gets called whenever a panic occurs, giving you a chance to record the failure before the program terminates or unwinds. It will not make an invalid state safe again. Its job is to capture enough context to debug the failure, alert someone, and shut down cleanly when possible. Here’s a simple example of setting a panic hook: And here’s a panic hook that sends structured JSON data to a crash reporting service: What’s Inside ? The struct contains the panic message (via ) and the source location where the panic occurred (via ). Be aware that both can leak sensitive information: file paths may reveal internal directory structure, and panic messages might contain interpolated user data. And finally, here’s Sentry’s panic hook handler , which is even more sophisticated: Sentry’s panic hook: There’s a lot to learn from these few lines of code! Panic hooks are also your final opportunity to prevent information leaks. The sensitive data can come from two places: the panic payload and the panic location. The payload is whatever your code passed to , , , or an assertion. That means it can contain interpolated user input, internal state from output, request headers, tokens, email addresses, IP addresses, customer IDs, or other identifiers. The location can expose source file paths, workspace names, or CI/build machine directory layouts. A well-designed panic hook sanitizes these messages before they reach logs or crash reports. Better yet, avoid putting secrets or raw user data into panic messages in the first place. Prefer stable error codes, request IDs, or redacted domain types. Regexes can catch obvious patterns like email addresses and bearer tokens. UUIDs and IP addresses can also identify users. Treat those checks as your final fallback. You can look into crates like expunge or veil to automatically redact sensitive information from structs: Before the process terminates, you might want to flush logs, close network connections, or notify other systems that this instance is going down. Setting a hook is a great way to perform such cleanup operations. Panic Hooks Run in a Compromised Environment Be careful: one of the subsystems you want to interact with might be the cause of the panic you’re handling! For example, if your database connection pool panicked, trying to flush pending writes to that same pool will likely fail or hang. Keep cleanup operations fault-tolerant and avoid anything that can panic, block indefinitely, or depend on the subsystem that just failed. Panic hooks only run for unwinding panics. If your program aborts on panic, or if the panic is caused by a stack overflow or out-of-memory condition, your hook won’t execute. Never rely on panic hooks for correctness. They’re purely for observability and graceful degradation; don’t try to recover from logic errors as it is very hard to rely on a system’s fragile underpinnings at this stage. Okay, you handle errors gracefully and you know how your system behaves on panic. Panic behavior isn’t the only runtime failure mode you need to worry about. Here’s some simple recursive code. What is wrong with it? The problem is that recursion can quickly exhaust stack space. If you allow users to call this function with large inputs, it might crash your program. Rust does not guarantee tail-call optimization on stable Rust . Some compilers and languages can turn certain tail-recursive functions into loops, but you should not rely on that transformation in Rust. If recursion depth depends on user input or external data, rewrite the algorithm iteratively or put an explicit bound on the depth. It takes some experience, but for recursive algorithms where you’re not in control of the input size, it’s often safer to use an iterative approach: One of the most dangerous assumptions in Rust development is that debug and release builds are functionally equivalent. They’re not. In many ways, you’re shipping a different program than the one you tested. The most obvious difference is integer overflow behavior. Debug builds panic on overflow, while release builds silently wrap around. We covered that in Pitfalls of Safe Rust . But the differences run deeper than arithmetic. Release builds remove checks, enable optimizations, and may exercise different code paths behind . Unsafe code and FFI boundaries are especially sensitive to this: undefined behavior can appear harmless in debug mode and break only once the optimizer starts relying on Rust’s aliasing and validity rules. Here is a trivial example: In a debug build, trips the . In a release build, the assertion is gone. The subtraction can underflow and wrap around, turning an invalid discount into a huge number. If the check protects a real runtime invariant, use or return a instead of relying on . The fact that tests pass in debug mode does not prove that production behavior is correct. Run normal debug tests as the fast default, and add release-mode tests for critical integration tests, arithmetic-heavy code, unsafe or FFI-heavy code, and anything whose behavior depends on optimization or release-only configuration. Your code is only as safe as your dependencies. You should regularly audit your dependencies for known vulnerabilities. Two helpful tools for that are and . It’s recommended to run those as part of CI. mimalloc is a drop-in global allocator built by Microsoft. What’s special about it is that it also has a secure mode , which adds mitigations like guard pages, randomized allocation, and encrypted free lists to make some heap-corruption bugs harder to exploit. 2 Safe Rust already prevents most use-after-free and buffer-overflow bugs, and a secure allocator does not magically make memory-unsafe code safe. This is mostly defense-in-depth for programs with unsafe code, custom allocators, C/C++ dependencies, or FFI-heavy boundaries. To enable secure mode, put this in : Then use it as your global allocator: Now, all heap allocations in your Rust program will use mimalloc’s secure allocator. Measure the performance impact on your workload before rolling this out broadly; allocator choice can matter a lot for latency-sensitive services, games, packet processing, and other allocation-heavy programs. Even well-written Rust code can be compromised through its dependencies, environment, or C FFI boundaries. The idea is to reduce your blast radius. Now, how you do that depends on your deployment environment, but generally people use Docker and Linux, so I thought I’d share some techniques for those; specifically, how to build minimal container images and filesystem sandboxing. A minimal production image contains exactly what you put in it. Even if your service is compromised, the attacker has very limited tools at their disposal to do further damage. My recommendation is Google’s distroless images , but please do your own research 3 as I’m not an expert on this. Distroless images are minimal Debian-based images stripped of everything unnecessary, while still including TLS certificates and a non-root user. For a typical Rust web service, start with : it includes the C runtime libraries that a normal Debian-built Rust binary may dynamically link against, but no shell or package manager. (Check the latest version in the distroless README .) Here is an example Dockerfile using for dependency caching: Take this Dockerfile as a starting point, but please adapt it to your own project requirements. keeps dependency builds in a separate Docker layer, so changing your application code does not force all dependencies to rebuild. The important details are: use the same Rust version in all build stages, build with , scope workspace builds with when appropriate, and keep , , and editor files out of the build context via . For a deep dive on Docker images and build-time optimization, see Tips For Faster CI Builds . Keep the Debian suffix explicit instead of using the unversioned tag, and pin by digest if reproducible deploys matter to you. If you deliberately build a fully static musl binary, then or even can be a better fit. But don’t mix the two approaches: a glibc-linked binary needs a runtime image that provides the libraries it links against. A Note On Alpine Base Images Alpine base images are a well-known alternative, but they use musl instead of glibc. That can expose differences in DNS resolution, TLS/native dependencies, allocator behavior, and crates that assume a glibc-like environment. ( 1 2 3 ) That doesn’t mean Alpine or musl are wrong; just treat them as a deliberate target and test them like one. If you build on Debian and want a small runtime image, distroless is usually the less surprising default. Even inside a minimal container, your process still has access to any file the container mounts. Landlock is a Linux security module that lets a process restrict its own filesystem access. If your service is ever exploited, the attacker can only reach the files you explicitly allowed. 4 Landlock Is Deployment-Specific Landlock is Linux-only and requires kernel support. It landed in Linux 5.13, but older enterprise kernels, custom cloud images, or container hosts may not enable it. Check your actual deployment target. Also apply the sandbox only after you know which files your process needs. If your service executes helper binaries from , reads timezone data from , loads certificates, opens SQLite files, reads config from , or writes uploads to , those paths must be allowed explicitly. On non-Linux targets, look for equivalent sandboxing mechanisms instead of copying this exact snippet. Call as early as possible in , before spawning threads or accepting connections. The restrictions apply to the entire process from that point forward. The two approaches really go hand in hand: Don’t run as root in production, even inside a container. That’s one reason distroless images provide a user and why the example above uses the tag. If your service only needs to listen for HTTP traffic, prefer a high port like over running as root just to bind to port . Linux capabilities are another useful lever. Instead of giving a process full root privileges, grant only the specific capability it needs, such as for binding to low ports. If a process needs elevated privileges only during startup, drop them before accepting requests. The details vary by platform and orchestrator, so treat Linux containers as one concrete setup. For systemd services, Kubernetes, FreeBSD jails, macOS sandboxing, or Windows services, look up the equivalent least-privilege and sandboxing features for that environment. The big picture is that security hardening is about reducing the surface of things that can go wrong. Every capability your process holds unnecessarily is a liability and everything your code manages that could be delegated to the OS, init system, or container runtime probably should be. Miri is an interpreter for Rust’s mid-level intermediate representation (MIR) that can detect undefined behavior at runtime. It works by executing your Rust code in a special environment that tracks memory accesses, pointer validity, and other low-level details to catch issues that the compiler can’t statically guarantee against. More people should know about Miri, because it is really helpful for hard-to-detect race conditions in multi-threaded or async code; but it can do way more than that, of course. It has already detected a lot of real-world bugs , even in the standard library. Using it is as simple as running: This will run your tests under Miri’s interpreter. The docs also describe how to add miri to CI : (Make sure to check the latest instructions in the Miri repo, as the setup process may change over time.) If you’d like to learn more about Miri, there is a research paper from 2026 that goes into the design and implementation details: Miri: Practical Undefined Behavior Detection for Rust . A hardened service doesn’t just crash. Instead, it shuts down gracefully when asked. Aim to finish in-flight requests, flush your buffers, and release resources cleanly before you exit. The pattern is: listen for shutdown signals, stop accepting new work, drain existing work, then exit. Frameworks like Axum have built-in support for graceful shutdown . Use it! The key is handling signals like (sent by Kubernetes, systemd, or ) and (Ctrl+C). Here’s a minimal example using tokio-graceful-shutdown , which is a crate that provides good signal handling without much boilerplate. It introduces a concept of “subsystems” that can run concurrently and listen for shutdown requests. When an external service (database, API, cache) starts failing, you don’t want to keep hammering it with requests. A circuit breaker tracks failures and “trips” when a threshold is reached. For production use, consider crates like or the more actively maintained , which is based on failsafe. Unbounded resources are a common source of runtime failures. Everybody who was on call for a production service will tell you this. Set explicit limits on everything . SREs will thank you for it! Limits make your service more predictable, and they make misconfigurations obvious sooner. Common things you should limit include: Here are some examples of how to do this in practice: See Axum’s : Bound the number of items in every queue or channel in your system. Every unbounded resource is a potential DoS vector. Explicit limits turn those catastrophic failures into (annoying but harmless) graceful rejections. Ideally, your system should be able to recover from transient failures without human intervention. Health checks let load balancers and orchestrators know when something is wrong, so they can react. A typical setup has two endpoints, a liveness probe and a readiness probe. The liveness probe checks if the process is alive at all, while the readiness probe checks if the process is healthy enough to handle traffic. This could honestly be an entire article on its own, but here’s a quick example using Axum to illustrate the concept: What’s neat about it is that this maps directly to Kubernetes’ health check system: Do we really need both probes? Yes, because they serve different purposes: Finally, here are some more tools that help you catch problems before they hit production: The tools above help catch undefined behavior, memory safety issues, code coverage gaps, and performance bottlenecks. They are dynamic analysis tools that complement Rust’s static guarantees. This only holds for unwinding panics. If you compile with , or hit a stack overflow or out-of-memory failure, the whole process exits and never gets a chance to return . ↩ https://docs.rs/mimalloc-safe/latest/mimalloc_safe/ ↩ Data sources I found useful for this topic include this post and this comparison . ↩ This approach would have prevented a vulnerability in Meta’s crate , a tool for recording and displaying system data like hardware utilization and cgroup information on Linux. ↩ make your code resilient at runtime harden your Rust code for production know how Rust code can fail in unexpected ways and how to recover from that Panic Semantics Are Part of Your API Unwind vs. Abort Thread-Level vs. Process-Level Failures Observing Failures With Panic Hooks Example Panic Hooks Sanitizing Sensitive Data Cleanup Operations Limitations Stack Overflows And Runtime Behavior Release and Debug Builds Are Two Different Programs Testing Release Behavior Supply-Chain Security Secure Allocations With mimalloc Limit Your Runtime Attack Surface Minimal Docker Images Filesystem Sandboxing With Landlock Drop Privileges and Capabilities Miri: Detect Unsafe Code Issues Graceful Shutdown Handling Circuit Breakers for External Dependencies Resource Limits Request Body Size Limits Limit Queue Depth Set Timeouts on Everything External Health Checks and Self-Healing Runtime Hardening Tooling Panics that would unwind across an extern “C” boundary are defined to abort instead of unwinding, because letting unwinding cross that boundary is undefined behavior . And if a fails, it aborts the process . If that’s a problem, you need to proactively check for allocation sizes before allocating or avoid heap allocations altogether. Logs the panic information Preserves the previous panic hook behavior by calling Ensures the hook is only set once using minimal images limit what’s in the container Landlock limits what the process can touch at runtime. Upper bound on any user input (upload file size, parameter bounds, etc.) request body size timeouts on external calls concurrent connections to external services queue depth for background jobs thread count and DB connection pool size Kubernetes stops sending traffic (graceful degradation) if the readiness probe fails. It does not yet kill the pod. Kubernetes restarts your pod if the liveness probe fails (it’s self-healing!) – fuzz testing for Rust code – another fuzzer with Rust support – detects usage of unsafe code – runs Valgrind on Rust code to find memory errors – code coverage via rustc/LLVM source-based instrumentation ( ). It reports line and region coverage, works with and , and is a good default for new projects. – an older Rust coverage tool with strong Cargo and CI ergonomics. On Linux it defaults to a backend ( only); LLVM coverage is available through and is the default on macOS and Windows. Useful if its reports fit your workflow, but expect different platform and test-runner edge cases than . This only holds for unwinding panics. If you compile with , or hit a stack overflow or out-of-memory failure, the whole process exits and never gets a chance to return . ↩ https://docs.rs/mimalloc-safe/latest/mimalloc_safe/ ↩ Data sources I found useful for this topic include this post and this comparison . ↩ This approach would have prevented a vulnerability in Meta’s crate , a tool for recording and displaying system data like hardware utilization and cgroup information on Linux. ↩

0 views
iDiallo Yesterday

Expensive Is Just a Brand Now

You've probably heard this one before. It might have come from a parent, a teacher, or a friend who bought an expensive item and wanted to justify it. It goes something like this: A poor man buys a cheap pair of boots for a few dollars. They fall apart within a year, so he buys another pair. And another. Over five years, he spends far more than the man who bought one expensive, well-made pair up front. A pair that's still going strong to this day. And the lesson was simple: buying cheap is expensive. Buy quality, and you save money in the long run. Now swap the boots for a jacket, a phone, a kitchen knife, whatever you like. In my experience, that used to be true. I have old clothing still hanging in my closet, and they still hold together. Price and quality were correlated. If a company was going to charge you more, it needed to justify that premium with better materials, better construction, better everything. The market punished brands that didn't. But something changed along the way. This is just my own personal observation, but I'm sure you can relate: I pay too much for things that don't last. When I was growing up, we separated the real from the knockoff with a simple test. You flipped the product over and checked the tag. If it said "Made in China," you knew it was a cheap knockoff. Then, somewhat suddenly, that stopped working. Walk into almost any flagship store for almost any prestige brand today, and check the label. Chances are it says the same thing as the bargain version sitting in a discount bin three blocks away. They all come from the same factories, the same supply chains, and in some cases, the very same production line. It's not the quality of the product that determines the price. What determines whether a good sells for $30 or $300 depends entirely on the brand. Right above the "Made in China," you'll now find another line: "Designed in [prestigious country here]." The materials didn't necessarily get worse. But the price no longer tells you what it used to. When you pay that premium now, the price covers the ad campaigns, the celebrity endorsements, the logo, the history, the feeling of exclusivity, and the envy from your friends. Today, price is not a proxy for quality. Businesses are simply capitalizing on brand power, that's all. When you buy something expensive, you have no guarantee that it will last. Everything should be judged on a case-by-case basis. In fact, if you're looking for goods that last, one approach is to search for "cheap alternatives" online. The story we were always told was really about information. The poor man didn't have the money to buy quality, so he used price as a signal to gauge quality, and maybe saved up to invest in a better product. That rule has changed. Price is now just a signal of a brand's power, nothing else. To find the better product, you'll have to rely on others who've tested it and can tell you how it holds up to time.

0 views

Opaque, Interoperable Passkey Records (and a Go API)

Passkeys are the most important thing happening in information security right now because they are the only principled solution to the overwhelming effectiveness of phishing attacks. Just like memory safety is the only principled solution to memory corruption attacks. Unfortunately, implementing them on the server side can appear more complex than using password hashes. Part of this is unavoidable because passkeys require interaction with the browser to get their phishing resistance properties. Part of it, however, could be abstracted away a little more effectively by defining interoperable passkey record encodings. The WebAuthn specification defines a credential record as an abstract concept with a number of components such as , , , , , and other flags. Google recommends a database table with a Credential ID primary key, and , , and columns. Adam Langley’s stellar Tour of WebAuthn similarly recommends a primary key, and separate and columns. All guidance recommends using libraries to handle WebAuthn authentication, but that still leaves applications with a potentially non-interoperable database schema. It might also be impractical to defer the whole authentication flow and database interaction to a library or framework. Interoperable, well-specified passkey records that the application can handle as opaque strings, like password hashes, can be a middle-ground abstraction layer. c2sp.org/passkey-record is a specification proposal which borrows the syntax of Password Hashing Competition (PHC) Strings and reuses the existing authenticator data encoding for the bulk of the work. A record looks like this: The payload is the authenticator data, a binary encoding of most of the credential record fields that is already specified by WebAuthn and included in the JSON encoding of an AuthenticatorAttestationResponse (which is the return type of even if attestation is not in use). Transports are the only missing field, and they are stored as PHC parameters. The application is then only in charge of keeping track of what passkey records are associated with a user account, which is a task that is familiar to web developers because it is not dissimilar to implementing password authentication (except there are multiple passkeys per account). These opaque strings can be passed to a library to verify the login assertion (or to generate a registration request with the appropriate ). With a well-specified interoperable storage format, it will hopefully be possible to switch passkey library (or even backend language) while preserving a credentials database. Along with the passkey record, applications might still wish to store metadata fields like a user-selected nickname and creation and last use timestamps, to provide pretty passkey management UIs. None of these require any special treatment by the WebAuthn library. The one exception is the backed up state flag. Passkeys report to the server whether they are backed up (e.g. to iCloud Keychain or a Google account), and servers can use that signal to suggest removing a password from an account. This flag can change across logins, while the passkey record is immutable, so it would have to be stored separately and updated on every login. I think this logic is overrated for the average website, which will keep supporting email password resets anyway. Building on top of these passkey records, I drafted a potential stateless Go package API . The registration flow is The login flow is The application is in charge of The library provides JSON values that can be passed straight to and , and accepts JSON values returned by calling on a PublicKeyCredential . This is optimized for the discoverable credential flow (a.k.a. passkeys, where the authenticator stores and provides to the server the user ID) but the method can also be used for second-factor flows or re-authentication prompts. The API works for both modal and conditional UI (autofill) flows. There are a few helpers to extract information from the passkey record ( , ) and from the JSON-encoded PublicKeyCredential ( ). Currently, there is no implementation; I would like to get feedback on the passkey record format and on the Go API , before potentially making a proposal for Go 1.28. One thing you can’t do with this storage model is ensure that different accounts don’t share passkeys with the same Credential ID, which the spec says you SHOULD do. The reason for that check is avoiding attacks where you look up a credential by its ID and land at the wrong public key or user ID because the attacker intentionally injected a colliding Credential ID through their own account. This attack simply can’t happen if you don’t have a Credential ID index in the first place! The index is only needed to mitigate an attack introduced by the existence of the index. Login attempts carry the user ID, and if you use that to look up the user’s passkey records to verify the login against, it doesn’t matter if some other user has a passkey with the same Credential ID, just like it doesn’t matter if two users share a password. Don’t let the attacker dictate your PRIMARY KEY and you won’t have PRIMARY KEY collision attacks. For more Go API previews, follow me on Bluesky at @filippo.abyssdomain.expert or on Mastodon at @[email protected] . More from this year’s CENTOPASSI (a GPS-tracked motorcycle competition involving careful planning, 100 coordinates, and 1700 km of secondary roads over three and a half days). Here’s a glimpse of Castel del Monte (AQ), after climbing down from a deserted and still snowy Campo Imperatore. My work is made possible by Geomys , an organization of professional Go maintainers, which is funded by Ava Labs , Teleport , Datadog , Tailscale , and Sentry . Through our retainer contracts they ensure the sustainability and reliability of our open source maintenance work and get a direct line to my expertise and that of the other Geomys maintainers. (Learn more in the Geomys announcement .) Here are a few words from some of them! Teleport — For the past five years, attacks and compromises have been shifting from traditional malware and security breaches to identifying and compromising valid user accounts and credentials with social engineering, credential theft, or phishing. Teleport Identity is designed to eliminate weak access patterns through access monitoring, minimize attack surface with access requests, and purge unused permissions via mandatory access reviews. Ava Labs — We at Ava Labs , maintainer of AvalancheGo (the most widely used client for interacting with the Avalanche Network ), believe the sustainable maintenance and development of open source cryptographic protocols is critical to the broad adoption of blockchain technology. We are proud to support this necessary and impactful work through our ongoing sponsorship of Filippo and his team. call with the logged-in (or otherwise identified) user details and any existing passkey records pass the returned JSON to and then to pass the returned JSON-encoded PublicKeyCredential to store the returned passkey record in the database call while generating the log-in page store the returned request in a key-value cache with a short TTL, under , and pass the returned JSON to and then to pass the returned JSON-encoded PublicKeyCredential to , and use the returned requestID to retrieve the request from the key-value cache and use the returned userID to retrieve the passkey records from the database pass the JSON PublicKeyCredential, the request, and the passkey records to associating an opaque, permanent, privacy-preserving user ID with each user; storing passkey records associated with a user; and caching request challenges produced by .

0 views

Kuiper Q-Q plot: are these the same?

When we tried to get an intuition for the differences in distribution functions, we learned that children subjected to a treatment had greater variation in their score than the reference group. (Continue reading the full article on the web.)

0 views
Unsung Yesterday

Five moments in snapping history

Bear (a notetaking tool) has simple image resizing, with one extra nicety – if your images are near each other, resizing one will snap to the width of the other: In the Finder, columns snap to the width necessary to keep all the names untruncated – and not one pixel more: (Sidebar: This is also the only place I’m mentioning today that nicely uses the trackpad’s haptic feedback at the snap moment. I tried to indicate it in the video; this is not the final visual treatment I’m thinking of, but let me know if this kind of visualization of haptics feels useful to you!) macOS does something really interesting when you get its windows close to each other. Instead of typical snapping – pulling the thing you hold toward the other item like a magnet – it instead prevents you from going further for a while, in either direction. Perhaps the right analog here would be glue : If initially feels a bit funny, but I think I like it. It’s less aggressive and avoids needing some sort of cancellation (an option or a modifier key) if you don’t want it, because it never feels in a way. It also works for matching heights, like in Bear: In Figma, building atop regular snapping, we introduced something I awkwardly called “self-snapping”: if your objects are inside a container, the container will snap its padding to whatever it sees on the other side, without any explicit auto layout/​flexbox: I am sharing these five examples (and one from before ) because I think they exemplify a nice thing: precision without bureaucracy. In each case you could imagine an explicit heavy option somewhere in the menu… …that would feel slow and cumbersome. Instead, these take the freedom of direct manipulation and sprinkle just enough almost-invisible structure in a moment where that structure is undeniably useful. (Of course, you still might want explicit options somewhere in the menu or your command palette, if only for accessibility reasons.) I like that these quiet features have your back and make you look good, and that their creators understand that something almost aligned can feel worse than something completely misaligned. #bear #complexity #direct manipulation #interface design #mouse Bear: Set Image Width… macOS: Match Window Heights Finder: Restore Column Width Figma: Unify Padding

0 views
matduggan.com 2 days ago

I added a blogroll

I realized that it might be nice if you happen to stumble on this website if I had a way to recommend other websites you might enjoy. As it turns out this is a "blogroll", a concept I have never heard of before today but whatever. It's still a good idea. I tried to add some CSS to make it easier to follow and search, but let me know if you think I missed a great site that people should check out. I'm also always on the hunt for more good stuff to read. You can find my email and social on the About page above. Also if you want to just take this Ghost theme and use it yourself feel free: https://gitlab.com/matdevdug/minimal-ghost-theme Anyway here is my new blogroll: https://matduggan.com/blogroll/

0 views
Stratechery 2 days ago

Who’s Afraid of Chinese Models?

Listen to this post : There’s a story I tell about my first day in STRT-431 at Kellogg School of Management, the introductory class that every first-year MBA was required to take; I leafed through the readings and case studies and was dismayed that there weren’t any tech companies on the docket. Me being me, I spoke to the professor after class wondering why, and was told that the goal of the course was not to necessarily learn about specific industries, but rather to uncover broadly applicable universal principles that could be applied to any company in any industry. I did not, as I usually tell the story, find this very satisfactory: to me the nature of tech, particularly the fact that software and distribution had zero marginal costs (and zero transaction costs), was something fundamentally different; putting in zeroes in formulas tends to wreak havoc! I soon realized, however, that that was my opportunity. The fundamental insight undergirding Aggregation Theory is that zero marginal costs leads to fundamentally different value chains than people once expected from the Internet: centralization and scale in a world where controlling demand mattered more than distributing supply. What is fascinating about AI, however, is the extent to which those old universal principles are coming back to the forefront. That was never more apparent than this past weekend, when arguments raged on X about the implications of Kimi K3, another open weights model out of China, approaching the state-of-the-art in terms of capabilities. The long and short of it is this: marginal costs are back in a big way, both in terms of short-term implications of state-of-the-art free models, and in terms of the long-term structure of the industry. One of the most common misconceptions undergirding discussion of open weights models is that they are cheaper — free, even. After all, you can just download the weights, and skip the time and expense and capabilities necessary to create your own model. That is, of course, true, but the “free” in this case is a reference to the amount you need to spend on research and development; R&D is a fixed expense that is independent of the revenue you generate. If you spend $1 million in R&D, it doesn’t matter if you do $100 thousand in revenue or $100 million; you still spent $1 million on R&D (it does, of course, impact your profitability). What is related to revenue is COGS — cost of goods sold — and COGS is real for AI in a way it hasn’t been for software for a very long time. Specifically, running inference on a model — whether that model be Kimi or Fable — costs money, and the amount of money an AI provider spends on inference is, at least in most business models, directly correlated to revenue. To reuse the above example, generating $100 million versus $100 thousand in revenue will likely require 1,000x COGS. In concrete terms, if it costs 50 cents to generate the tokens that drive $1 in revenue, then $100 million in revenue will have $50 million in COGS; $100 thousand in revenue will only have $50 thousand in COGS. The point in terms of open weight models is that they are not free to serve. Kimi K3 costs $3 per million input tokens, and $15 per million output tokens; that is cheaper than Sol’s $5 per million input tokens and $30 per million output tokens, but that might not even be the right measurement. Nvidia CEO Jensen Huang has described what Nvidia is building as “token factories”, and from Nvidia’s perspective that framing makes sense. Nvidia GPUs are model agnostic: they generate tokens, and do so in the fastest and most efficient way possible. That leads to measurements like tokens-per-second, time-to-first-token, tokens-per-watt, token cost, etc., and Huang argues that these metrics will be the basis for decision-making. This is a framing that definitely made sense during the first paradigm of AI, the ChatGPT era, when tokens were delivered straight to the end user. The second paradigm of AI, however, the reasoning era, confounds this measurement. Reasoning entails an explosion in chain-of-thought tokens, and different models need different amounts of reasoning tokens to arrive at the right answer. Kimi, for example, reportedly uses significantly more tokens than Sol, rendering its price advantage moot. Agents introduce a similar dynamic: some models are more efficient than others in terms of the number of tokens they need to execute agentic workflows. What this means is that tokens are not a commodity. The defining characteristic of a commodity is that it is fungible: a gallon of oil is a gallon of oil; a ton of copper is a ton of copper; a bushel of wheat is a bushel of wheat. A token from one model, however, is not the same as a token from another model. What is fungible is what is constructed from tokens, which is to say intelligence. In other words, if both Kimi and Sol generated the right answer, then that answer is fungible; the difference in tokens generated to get to that right answer is a contributor to a difference in COGS. The COGS for intelligence is a function of a few different factors: The reason this matters is that we are rapidly approaching a state in which intelligence for many economically beneficial tasks is in fact a commodity. Anyone building a basic CRUD app , for example, can likely do so using models from multiple providers. And, in a commodity market, the route to profitability is not through charging higher prices — again, you can (or will soon be able to) make the exact same app using multiple models — but rather through having a superior cost structure. It’s worth stepping through the mechanics here, because, as I noted a few months ago in Amazon’s Durability , the dynamics of commodity markets are not something people in tech are generally familiar with: The key thing to understand is that the marginal cost of producing the commodity differs by supplier. What this means in practice is that the supplier with the worst cost structure ends up selling the commodity at their marginal cost (if they can produce at all); the profits of everyone else depend on the extent to which their cost structure is better than the marginal supplier. As an example: Let’s assume the price elasticity is such that there is demand for 25 units of the commodity at $20. That means: This isn’t precisely right: the reason why Supplier C will bear the shortfall is because Suppliers A and B will be able to slightly undercut them in price, which will of course affect demand (which is elastic), but it makes the point. Supplier A has a great business, Supplier B has a good business, and Supplier C is going to go bankrupt. Bankruptcy risk is where fixed costs come back to the forefront: Supplier C has both fixed costs (like potentially R&D spend) and also may have taken on debt to finance the equipment necessary to produce the commodity. It can’t price its commodity with these costs in mind — remember, the market-clearing price approximates the marginal cost of the highest-cost unit needed to satisfy demand — but those costs can absolutely drive the supplier out of business. And, if that supplier goes out of business, then prices go up, until another supplier decides to enter (or the other suppliers expand). Let’s bring this back to models. Right now, none of the above analysis applies because demand exceeds supply for frontier models, and supply is limited by a lack of compute. This compute shortage doesn’t just mean that a compute supplier like Nvidia makes very large margins, but also that Nvidia’s customers, like SpaceXAI, can turn around and resell compute at high margins as well to a company like Anthropic. Anthropic, meanwhile, can pay the markup because they can sell tokens with a higher markup still. It’s not just excess demand that gives Anthropic great margins, however: Anthropic and OpenAI likely have among the lowest costs per unit of frontier-quality intelligence, thanks to model capability, serving scale, and token efficiency. They are serving models at a particular capability level for months before their competitors, and are simultaneously applying the best models to optimizing those costs. It’s also worth noting that the market is not yet treating intelligence like a commodity: demand is for Anthropic and OpenAI specifically, and much less for models that aren’t as good (thus SpaceXAI and Meta selling capacity to Anthropic); one way to think about the push for optimizing cost is that that is a function of defining jobs-to-be-done by intelligence level, such that intelligence buyers can create a market where intelligence is commoditized. In the long run, however, whoever is on the frontier is the best placed to dominate non-frontier markets as well, which are just the frontier minus n-months, i.e. months in which the frontier model makers have been optimizing their cost of serving. All of this is to say that I think the reaction to Kimi and Chinese models generally is pretty over-blown, at least from an economic perspective. Right now there is a price umbrella that is downstream of the lack of compute; I highly doubt that Chinese models are cheaper to serve on a marginal cost basis, they just seem cheaper because Anthropic and OpenAI are so supply constrained that they are charging far more than they would if there were sufficient supply to meet the demand for intelligence. Why, then, do the model makers in particular seem so panicked about Chinese models? First, I think the frontier labs are anchored in a world where training costs dominated their financial modeling. As long as training consumed more GPUs than inference, it was critical to maximize inference revenue to help fund the next training run, which meant charging very high prices for inference. Going forward, however, I expect the inference market to grow much faster than training costs (and that includes the assumption that training costs will continue to skyrocket), which means they really can make it up in volume. It wasn’t clear this would be the case as recently as eight months ago, but the agent paradigm unlock is so massive that frontier labs should have more confidence that they can not just survive but thrive with lower prices (once they have sufficient compute). Second, intelligence isn’t in fact a perfect commodity, in part because applied intelligence makes itself smarter. Specifically, whoever is running inference is also collecting data, and that data goes into making the next iteration of the model better. This is, on one hand, all the more reason for the frontier labs to lower prices and increase usage as more compute comes online; on the other hand, this is why companies like Microsoft are increasingly obsessed with helping companies run their own models. That is much more viable if Chinese models are a viable alternative. Third, the other way that frontier labs can not only differentiate from Chinese models but also from each other is by continuing to integrate up into the customer experience. It’s striking the extent to which Claude Code and Codex are proving to be quite sticky; whichever harness you start working with is likely to be the one you stick with, and that figures to be even more the case with non-technical users. And, in the long run, this imperative to move up the stack does mean that frontier models are absolutely a threat to software providers, including Microsoft. On the flipside, the extent to which software companies who currently own the customer experience have access to competitive models is the extent to which they may be able to resist the encroachment of the frontier labs. Finally, the ideological angle of Anthropic in particular is impossible to ignore. This is a company that believes only it can be entrusted with AI, and the existence of open weights alternatives strikes a fatal blow to that presumption. Kimi isn’t the only new Chinese model; from Bloomberg : Alibaba Group Holding Ltd. shares rose as much as 5.4% on Monday after the company launched a preview version of its flagship Qwen3.8 Max model, describing it as second only to Anthropic PBC’s Fable 5. The Sunday release came only days after startup Moonshot AI unveiled a powerful new offering that’s roiled markets and triggered concern in the US about China closing the gap on global leaders like Anthropic and OpenAI. Qwen3.8 Max has 2.4 trillion parameters, joining Moonshot’s Kimi K3 in the heavyweight class. With 2.8 trillion parameters, K3 rivals top offerings and Alibaba is setting similarly high expectations. Developers can now access Qwen3.8 Max through Alibaba’s coding platforms, including Qoder. Alibaba plans to make the model open-weight soon, expanding access beyond the preview release. Interest in these made-in-China artificial intelligence systems and models is so high that Moonshot was forced to pause taking on new subscriptions late on Sunday to manage overwhelming demand. The fact that Qwen3.8 Max will also have open weights is notable. Alibaba stopped releasing weights for its leading edge models earlier this year, but appears to have reverted that change; I suspect that shift was related to last week’s Xi Jinping speech about AI that doubled down on the open weights approach: We should adhere to the principle of openness and win-win and boost innovation-driven development. As a new engine of world economic growth and an accelerator for the shift of growth drivers, AI is moving from the digital world into the physical world. We should seize this rare, historic opportunity to encourage open source, openness, collaboration and sharing. We should facilitate technological innovation, industrial development and scenario-based application of AI. We should make coordinated advances in the transformation and upgrade of traditional industries, the cultivation and growth of emerging industries and forward-looking planning for future industries, so that all sectors and businesses can benefit from AI. The strategy for China is obvious: commoditize your complements. Note that Xi explicitly ties openness to AI “moving from the digital world into the physical world”; the physical world is the world dominated by China, and the country’s lead in areas like robotics is going to massively benefit from widely available AI models. Along the same lines, China does not want the U.S. to gain an asymmetric advantage in AI; to the extent that China can weaken the U.S. frontier labs while strengthening any and all potential U.S. adversaries so much the better, and it can benefit from the innovation that will attach itself to an open ecosystem. By the same token, don’t expect China to do anything about distillation attacks on the frontier labs. I think it is mistaken to attribute all of the success of Chinese labs to distillation, but it’s just as much of a mistake to pretend like distillation doesn’t give Chinese labs a big advantage. That advantage has really come to bear in the last year as post-training reinforcement learning has become increasingly crucial to model performance. Instead of having to fashion reinforcement learning environments from scratch, Chinese labs can simply use frontier labs models as teachers, allowing for rapid improvement at much lower costs (this is not the only reason why Chinese models are cheaper to develop, but it’s a big one). What is interesting is that one of the most important use cases for Chinese models in the West is itself distillation. Thinking Machines, for example, which just released an open-weight model, relies on Chinese models to solve the cold start problem for reinforcement learning. Dean Meyer and Konstantine Buhler wrote an excellent article on X explaining that distillation means that Western open weight models are fundamentally disadvantaged relative to China: Distillation does not explain China’s entire open-model lead. Chinese labs have world-class researchers, substantial compute, strong pre-trained models, software-hardware codesign, and rapidly improving post-training capabilities. But distillation compresses the costly final gap between a strong base and a near-frontier system. Even if distillation represents a smaller share of a Chinese model’s total capability, it represents a meaningful share of its advantage over American open models. New enforcement mechanisms will make large-scale distillation harder, slower, and more expensive for Chinese companies. However, enforcement will not eliminate distillation backed by state actors. Every Western frontier advance therefore creates another teacher for Chinese labs. Western builders must either reproduce those capabilities independently or wait to learn from Chinese models. This gap gives Chinese labs a recurring structural advantage over Western companies. This is a point that bears repeating: because U.S. open weight model makers must follow the frontier labs’ terms of service, they (1) are worse than Chinese alternatives and (2) end up distilling the distillation, just with a detour through Chinese labs. Wouldn’t it be better if western open weight model makers could go to the source? To that end, here’s an even more interesting question around distillation: why exactly is it bad? After all, what are large language models but the distillation of all of the knowledge on the open Internet, scraped by the frontier labs and distilled into the models that are themselves being distilled? Who is exactly being wronged here? In fact, this paradox is the solution. I believe that open weight models are good for innovation (and, per the above, I think that labs on the frontier will be fine), but it’s a problem to be dependent on China. The U.S. should pass a law that (1) makes explicit that collecting data for training models is fair use, and (2) bars terms of service that forbid distillation, for U.S. companies at a minimum. Stopping distillation — which is literally just querying the API — is nearly impossible; the U.S. should go the other way and lean into a new copyright policy that both indemnifies the labs and also guarantees that what they learned fuels further innovation for everyone else. This entire Article has been an exercise in defusing overreaction to Kimi K3 specifically and Chinese open weight models generally; however, there is one reason to be concerned, and that is cybersecurity. Consider this story from The Stack : Hugging Face said its production infrastructure was breached by an “autonomous” AI agent system early last week. The platform’s security team were initially stymied in their incident response (IR) by unnamed US LLM frontier model guardrails “which cannot distinguish an incident responder from an attacker,” they said. So Hugging Face’s defenders turned instead to the open-source GLM 5.2 model from China’s Z.ai lab – running it on their own infrastructure to analyse the 17,000+ logs, or footprints, that the attackers left behind. That’s a striking public admission for the New York-headquartered Hugging Face, which lets users collaborate on models, datasets and applications, and which this summer hit the $100 million ARR mark. In an incident report, the company recommended that defenders “have a capable model you can run on your own infrastructure [our italics] vetted and ready before an incident, both to avoid guardrail lockout and to keep attacker data and credentials from leaving your environment.” It’s difficult to overstate how wrong-headed the Trump administration’s panicked response to Anthropic’s release of Fable was, particularly since it exacerbated Anthropic’s worst tendencies in terms of assuming only they can be trusted with powerful AI. In a world with only one AI, it might make sense to reserve the most powerful cybersecurity capabilities for the U.S. government and trusted allies; however, that’s not the world we live in. There are and will be models eminently capable of mounting cybersecurity attacks on existing infrastructure, and those models will be — already are — widely available. The best defense — the only viable defense, in fact — will be to make sure defenders have access to the best models as well. Right now defenders are effectively banned from using Fable or Sol for cybersecurity because of Trump administration directives; that means the best alternative is using models from a country which has been trying to weaken our cyber defenses for years. This is insane! The better course is clear: first, loosen Fable and Sol restrictions on cybersecurity, and second, ensure that U.S. open weight model makers are on an equal playing field with China. Yes, the frontier labs will kick and scream about this, but the Administration should realize that listening to their histrionics has led the U.S. to a position where U.S. companies are dependent on China for their defenses. Let the frontier labs win by being better; don’t let them define safety or security, or pull up the ladder of humanity’s collective knowledge. China is already hard enough to compete with; letting them carry the standard for openness and innovation is simply giving away our biggest advantage. Model footprint: The weights and runtime state determine how much expensive memory and how many accelerators are required to host each serving replica. Inference efficiency: Architectural choices (e.g. Mixture-of-Experts) reduce computation per generated token. Memory efficiency: Architectural choices can reduce KV cache requirements, allowing more concurrent requests and better GPU utilization. Serving efficiency: Batching, scheduling, prefix caching, and other inference optimizations maximize utilization and share work across requests. Token efficiency: The fewer tokens required to reach a correct answer, the lower the inference cost. In commodity markets, everyone charges the same price, because everyone is selling the same thing; that price is determined by supply and demand. The demand for a commodity is a function of price elasticity: the cheaper the commodity, the more demand there is for it, and vice-versa. The supply for a commodity is a function of the marginal cost of producing the commodity. Supplier A can produce 10 units of the commodity for $10 each Supplier B can produce 10 units of the commodity for $15 each Supplier C can produce 10 units of the commodity for $20 each Supplier A will sell 10 units of the commodity for $20, earning $10/unit Supplier B will sell 10 units of the commodity for $20, earning $5/unit Supplier C will sell 5 units of the commodity for $20, earning $0/unit

0 views
Unsung 2 days ago

“Try quickly typing 1+2+3. I bet you won’t get 6.”

Earlier this month, I talked about a rotation button in photos that behaved really nicely in iOS, and not so great on the Nothing Phone . Here’s a story of a similar fumble iOS once made that might bring the point home even more. The calculator app has been preinstalled on iPhones ever since their debut in 2007. For the longest time it hasn’t been anything more than a standard four-function calculator with a decades-old feature set. If you’re not careful, however, you can mess up even that. Ten years into iPhone’s history, iOS 11 introduced a problem just like the Nothing Phone rotation – quickly tapping on keys would show them as responding, but the actual action wouldn’t be registered. Michael Tsai’s aggregator’s first entry has a video from Stephen Heaps: It shows typing 1+2+3+4 where iOS forgets one press of +, resulting in 1+23+4 = 28. Many more people posted about it afterwards, and showed various other examples . It is oddly enthralling to see a computer fail at basic math. But what’s particularly historically interesting and perhaps even more embarrassing for Apple is the absolutely rich history of solving this kind of a problem. Calculators evolved alongside typewriters as the earliest devices with button-like (as opposed to piano-like) keyboards. But the stakes were different. Imagine a badly constructed typewriter and all the ways it can disappoint you: the letter might be faint if you press the key lightly or puncture the paper if you press it too hard, the output might be misaligned, or the typebars will jam in some way, forcing you to go again. A typewriter has to work hard to divvy up a blank, analog piece of paper into a reliable grid via escapements, ratchets, and so on. But a calculator’s work to convince the analog world to be digital is more important. After all, it’s not likely that the typewriter key you pressed will output the wrong letter – but on a badly constructed calculator, a light press of 5 could absolutely output 4, or 6, or 4.5. And, while the typewriters only take your words verbatim, the calculator’s job is precisely to create new numbers out of the numbers you type. An imprecise mechanism can mess up that math. A jam could perform a partial or nondeterministic calculation. Adding 1 to 999,999 and the force necessary for the resulting cascading carry could break a device in the middle of work. On top of all that, languages have a built-in redundancy. Evn if yuo mak many typoes, th sentece can stil be understod. But all numbers basically look alike. A calculator could make a mistake when it comes to a number that is absolutely vital for your payroll, for engineering, or for navigation – and you would never spot it. Understanding all this, many calculator makers even already in the 19th century spent a wild amount of effort convincing people not just that their devices are helpful, and fast, and easy to use, but also that they can be trusted . Buttons were carefully weighted. Comptometers came with a locking mechanism. If a machine felt something didn’t go right, it would stop working and require a hard reset. The message was: “You can trust me, because I won’t ever show you bad math, and I’ll stop myself before I will ever lie to you.” Charles Babbage was so confident in his Difference Engine that he welcomed people to try to mess with its mechanical wheels in the middle of the calculation, confident even a sabotaged machine won’t ever make a mistake. Just like with the Selectric decades later , those things were solved by people who cared, in the much harsher mechanical conditions. Of course, I don’t expect everybody at Apple core iOS team to be a calculator UI historian (although it would be nice for at least one person on the team to be one!). It is embarrassing that no one on the team had enough imagination to realize that making a button respond to a quick press during animation, but not register it would cause all sorts of serious trouble. (The bug was fixed in iOS 11.2 by removing the animations, and subsequently the animations were brought back without the original problem in iOS 11.3.) But maybe the bigger embarrassment is that Apple didn’t have a battery of tests to run on top of the UI at various speeds, mimicking fingers of what must be millions of people using the calculator app. That, too, has been a standard procedure for decades. = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/try-quickly-typing-123-i-bet-you-wont-get-6/2.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/try-quickly-typing-123-i-bet-you-wont-get-6/2.1600w.avif" type="image/avif"> = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/try-quickly-typing-123-i-bet-you-wont-get-6/3.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/try-quickly-typing-123-i-bet-you-wont-get-6/3.1600w.avif" type="image/avif"> Those tests seemed missing in 2017. I hope 2+3+4 years later that’s no longer the case. #apple #bugs #flow #history #real world #touch

0 views
マリウス 2 days ago

Apple iPhone Air

tl;dr: I bought an Apple iPhone Air , not because I believe in Apple ’s self-congratulatory “privacy is a fundamental human right” marketing, but because after years of replacing Google Pixel hardware roughly every 18 months I have, again, reached the point where I need exactly one mobile device that will reliably run the closed-source financial, corporate and government apps that modern societies insist on. The Air is a fascinating piece of engineering, despite the new Liquid Glass in iOS being the UI equivalent of a bad car accident , and the device’s raw performance for things like mobile RAW photo development is, sadly, significantly ahead of anything Android offers in 2026. I still do not recommend using an iPhone as a primary device, because Apple remains a surveillance company. Long-time readers of this blog will know that I have spent the better part of the last decade trying to engineer my way out of the surveillance economy. I switched away from iOS and stock Android to GrapheneOS a long time ago, I run my own infrastructure , my own cloud , my own mail , my own Lastpass ( update ), my own Dropbox , my own search , my own Spotify , my own messenger , heck, even my own Zapier (sort of), and have generally tried to minimize the surface area that any single vendor has on me. The fact that I just spent a frankly absurd amount of money on a brand-new Apple phone should therefore probably come with an explanation, which is what this post is. It’s also a review of the iPhone Air itself, and a brief tour of how badly iOS has aged on a device that costs roughly the same as a decent used car in many parts of the world. Disclosure: I paid for the device with my own money. I have no relationship with Apple , and would honestly prefer not to give them my money in the first place. The opinions in this post are entirely my own. To understand why a GrapheneOS apologist would willingly buy a brand-new iPhone , it helps to know the road that led me here. The tl;dr is that for the past four years I have run a compartmentalized multi-phone setup , with one primary device on GrapheneOS that is as clean of corporate spyware as it gets, and one dedicated spyware phone that runs all the banking, travel, government identity, and other apps that I have to use to participate in modern society , but that I refuse to have anywhere near my actual life. The iPhone Air is the latest incarnation of that second device. Before the Air I kept an iPhone 11 Pro Max around for almost seven years. Of every smartphone I have ever owned across the past two decades, the only two devices that survived such long periods of time without a single hardware-level fault were the Motorola Razr V3i (yeah, I’m that old) and the iPhone 11 Pro Max . And with most of the banking, government, and corporate know-your-customer software that I am forced to interact with on a regular basis simply refusing to run on a de-Googled device, and, more importantly, being a gigantic PITA to recover onto any new phone if the current one should ever give up, it made sense to keep one rock solid device around that I could rely on. And because iOS is the best-supported target for specifically these apps, the iPhone is the only realistic alternative for someone who refuses to deal with Google Play Services . Running this kind of software on a separate physical device, that is kept in a Faraday bag when not in active use, is the cleanest way I have found to limit the blast radius of surveillance capitalism. In other words, the iPhone 11 Pro Max was not my phone , but more like my spyware appliance . The decision to specifically go with the iPhone (17) Air , as opposed to a more mainstream iPhone 17 or even a used predecessor, came down to two things: form factor, and longevity. I wanted a device that wouldn’t add a ton of weight to my travel setup , yet was still capable enough to survive (ideally) the next decade. I intentionally didn’t buy a used iPhone , because I’m planning for this device to hold up for a very long time, so I wanted Apple ’s initial one-year warranty, plus the reassurance that no previous owner had beaten up the battery, burned in the screen or let the device melt or freeze in their car for hours. For a spyware phone that occasionally rides along in a pocket as a backup, or that travels along in my carry-on, I do not want a brick. The iPhone 11 Pro Max that I am retiring weighed a frankly miserable 226 grams and the current iPhone 17 Pro Max is even heavier at 233g. The non- Max variant is only slightly lighter at 206g, and even the regular iPhone 17 , despite having a .2" smaller screen, is still 12g heavier than the Air . The iPhone Air , by contrast, is 5.64mm thin (excluding the camera plateau) and weighs only 165 grams, all while carrying a 6.5" OLED display. For comparison, the Google Pixel 6a , which for some time had been my spyware device and that the Air is also replacing, is a 6.1" device made predominantly of cheap plastic and glass, and weighs 178g. That’s 13g more than the larger and sturdier iPhone . The Air is, by far, the lightest 6.5" flagship I have ever held. While its footprint is significantly larger than I had expected from photos, and it is definitely not a one-handed device for people with small- to medium-sized hands, if you, like myself, are coming from a Pro Max , you will probably feel like you are holding a piece of cardboard, and I mean that in a positive sense. With most of the mobile phone industry having converged on the same slab-of-glass-with-a-camera-bump template, and the differentiators usually being marketing language rather than actual engineering, the iPhone Air is somewhat of an exception. The frame is Ti-6Al-4V , which is supposedly made with 80% recycled titanium . And while Apple has used titanium on Pro -line iPhones since, I believe, the 15 Pro , the Air clearly pushes the thickness budget to a different level. The closest competitor in the realm of well-established premium smartphones, which I believe is the Samsung Galaxy S25 Edge , is slightly thicker and is shown in many reviews to have build-quality compromises. Because the Air is too thin to fit a conventional stamped USB-C connector, Apple ’s engineers 3D-printed the metal connector frame out of titanium powder, fused with a laser, and machined to spec. As reported by Engadget , Apple ’s justification is that at this thickness, there is no other way to fit a standard-compliant USB-C connector. I am skeptical of the claim that this was the only option (a redesigned stamped part would presumably also work), but the fact that they shipped a 3D-printed titanium structural component in a consumer phone is an interesting engineering choice. Another interesting engineering choice is the camera plateau . Rather than the widespread camera trypophobia bumps , the Air has a raised horizontal rail at the top of the back, under which sit the A19 Pro SoC , the new C1X modem, the networking silicon, and the single 48MP Fusion camera. This concentration of components in a thicker strip is what makes the rest of the chassis flat. From a thermal perspective it makes total sense, as it concentrates the device’s heat generation in a region that is the easiest to keep away from the user’s hand. This is one thing that always bugged me about the 11 Pro Max , which is that the moment the device is under load (which is pretty much all the time when running a recent iOS version) the backside area, where your fingers naturally rest when holding the phone, will get uncomfortably hot. On the Air you need to actively move your fingers underneath the plateau to feel the heat. However, because the Air does not have the vapor chamber that the Pro line introduced this generation, it throttles more aggressively under sustained load than the 17 Pro . For my use case (banking apps, occasional photo editing, very occasional video) this is irrelevant, but for someone trying to play a demanding game for two hours straight, it probably isn’t. Speaking of heat, the Air packs quite a lot of it with its 6-core CPU with 5-core GPU and the Neural Accelerators , which in benchmarks scores 9,497 points in Geekbench 6 multi-core. For comparison, the Pixel 10 Pro ’s Tensor G5 , in the same benchmark, sits at roughly two thirds of that number . The C1X modem, which is Apple ’s second-generation in-house cellular modem, is also an interesting piece of engineering. It has replaced the Qualcomm silicon that has been in every iPhone since the 12 and in real-world testing the C1X appears to be noticeably more power-efficient than both the Qualcomm modem in the 16 Pro and the Samsung Exynos 5300 modem that has been making the Pixel family miserable for the past several generations. For a device whose battery is a comparatively modest 3,149 mAh , that efficiency gain is what makes the Air ’s battery life usable at all. One big difference from literally every phone that I have ever owned is the fact that the Air has no physical SIM tray. If I were planning to use this phone as my primary phone, this would be a huge PITA for travel . Pre-paid SIMs in many countries are usually not available as eSIM, or when they are, they’re significantly more expensive and privacy-invasive due to KYC measures. I have written before about why I strongly prefer physical SIMs for both privacy and practical-travel reasons, and Apple ’s decision here is a real downside for any full-time traveller . The reason for the lack of a physical SIM tray appears to be that Apple needed the volume for the already small enough battery, which makes sense. It is nevertheless a regression. Another engineering decision that somewhat made me question the whole thing is the USB port. In 2026 the world’s most valuable company decided that, on a flagship-priced device, you still only get USB 2.0 transfer speeds out of the USB-C port. For whatever reason, Apple reserves USB 3 speeds for the Pro line. This means that transferring 50MB RAW files off an SD card via a USB-C card reader is not exactly slow , but it is also not fast , and it is straightforwardly insulting on a device as expensive as the iPhone Air . Plus, the whole USB design choice also leads to absurd incompatibility issues with plenty of built-in USB controllers within SSDs, making a good number of external drives simply unusable with the Air . One big letdown at this price point for many people seems to be the single 48MP rear camera. Coming from an iPhone 11 Pro Max , or even the cheaper Pixel 6a , both of which had multi-camera arrays, I understand that the average user might perceive this as a step down for photography. However, personally, I don’t care too much as I take essentially all of my photos on dedicated cameras anyway. GSMArena ’s review calls the single rear camera the device’s “big pain point” , and I think that is fair at this price. Taken together, the Air is probably the most opinionated phone Apple has shipped in a long time. The company was willing to sacrifice camera count, port performance, and thermal headroom to deliver a piece of hardware that is as thin and light as it is, and that is built around in-house silicon. Whether this approach turns out to be a good idea, history will tell. As a piece of standalone consumer electronics, however, it is pretty impressive, and I say that as someone who, in almost every other domain , finds modern consumer hardware profoundly depressing . And then there is the software. iOS 26 ships with Liquid Glass , Apple ’s new design language, which applies a translucent, light-refracting, glass-like aesthetic to basically every system surface, from the lock screen to the notifications, Control Center, app icons, menus, and even system alerts. Apple ’s clearly high af marketing department describes it as “a new material that combines the optical qualities of glass with a fluid, responsive feel that brings depth and dynamism to every interaction” … whatever that is supposed to mean. What it actually feels like, in daily use, is sadly less flowery , and the user backlash and performance issues have been covered extensively . The kindest thing I can say about Liquid Glass is that, despite it being the Ferrari Luce of UIs , the engineering underneath it is impressive. The amount of real-time blur, refraction, and material simulation Apple is pulling off on the A19 Pro at 120Hz is a graphics feat that the Android system can only dream about. Having said that, however, I don’t think that any of that engineering would be truly necessary if somebody at Apple had asked the question “does this design language actually make the device easier to use?” before shipping it on a billion devices. The primary purpose of the Air for me, as with its predecessors, is to host all of the closed-source corporate spyware that I refuse to put on my primary GrapheneOS device . This includes: On the Air , all of this just works . Apps launch instantly, attestation succeeds, and the device does not get anywhere near as hot as the average Pixel phone doing any of it. After four years of fighting with Google ’s hardware and Android ’s gradual decay, I am, embarrassingly, enjoying the boring reliability of iOS . The thing I did not expect, and the thing that has surprised me about the Air , is how good it is at mobile RAW photo development. For a long time I had been doing all of my photography workflow on a Pixel Tablet running GrapheneOS , using Lightroom Mobile . The arrangement worked, but it didn’t work well. Lightroom Mobile on the Tensor G2 -powered Pixel Tablet has increasingly become a sluggish, crash-prone mess , with editing operations that take noticeable seconds to render preview updates, occasional import failures, and a battery life under heavy editing that is less than three hours. On the iPhone Air , the same workflow (using a USB-C SD card reader, plus the free Snapseed app) is vastly faster. Importing a card full of 50MB RAW files from my Fuji is bottlenecked by the USB 2.0 port rather than the phone. Edit operations on RAW files are essentially instantaneous, even with multiple layered adjustments. Exporting to JPEG happens in well under two seconds per image. Obviously the Air ’s A19 Pro SoC was released several years after the Tensor G2 , and it is orders of magnitude faster on graphics workloads, but the Pixel Tablet is nevertheless a 2023 product that Google is still selling new in 2026. The fact that an in-pocket, 5.6mm-thin iPhone runs circles around it on the same workload is, frankly, embarrassing for Google . The mobile content-creation software ecosystem on iOS is also significantly better than what is available on Android , and not just because the hardware is faster. Lightroom Mobile on iOS is more polished than the Android version, and even Snapseed , an app by Google , runs noticeably more smoothly on iOS than it does on Android . Even free, ad-supported photo apps tend to be visibly better on iOS than anything on Android . Some of this is because developers prioritize iOS for revenue reasons, because literally every little sh.t app on iOS these days can seemingly charge a price or, worse, a subscription fee. However, some of it is also because Metal and Core Image are better-integrated graphics and imaging stacks than what Android exposes to third-party developers. Whatever the reason, in the specific category of mobile RAW photo development, iOS is not just ahead, but it is literally pulling Android ’s pants down and slapping its Baklava . Even setting RAW editing aside, the device feels noticeably snappier than any Android phone I have used, including the Pixel 8 . App launches are faster, animations are smoother, and background apps stay in memory longer. Apple ’s memory management on iOS , even with comparatively modest RAM (the Air has 12GB), is more aggressive about keeping apps warm than Android ’s. Tom’s Guide ’s real-world performance testing shows iPhones consistently lapping Android flagships on workloads like video transcoding, where the iPhone 17 Pro models complete a standard test in 22 seconds, while every Samsung Galaxy S25 variant takes over twice as long. On purely synthetic Geekbench 6 multi-core, the Snapdragon 8 Elite Gen 5 does outperform the A19 Pro , but the Snapdragon ’s lead in synthetic CPU benchmarks does not translate consistently into real-world responsiveness, because Android as an operating system still carries a significant amount of overhead that even the fastest silicon cannot entirely paper over. On the iOS side, the A19 Pro ’s single-core performance (around 3,871 points in Geekbench 6 ) is still the highest of any shipping mobile SoC. A heuristic that I have used for years, and that has consistently held up, is that an iPhone from year N tends to feel as snappy in everyday use as an Android flagship from year N+1 or N+2 , and I’m certain that the iPhone Air is no exception to that rule. This is a generic OS observation rather than a comment on the Air specifically, but it is a real observation, and it is one of the reasons why iOS devices keep getting recommended even by people who would much rather be using something else. Besides the superior hardware of Apple ’s phones over specifically the Google Pixel devices, the ecosystem of accessories that are intentionally designed to fit the iPhone lineup is another thing that Google , as well as most other Android manufacturers (with the exception of Samsung and Xiaomi ), has failed to establish. In recent years, Apple managed to further increase their ecosystem’s lead with their MagSafe quick-attach feature, for which you can find literally everything, from snap-on card holders through powerbanks all the way to actual stands. Because I was curious to give the MagSafe system a try, I decided to pick up a powerbank that unintentionally fits the “Space Black” iPhone Air better than Apple ’s own, plain white iPhone Air MagSafe Battery . I chose the Xiaomi UltraThin Magnetic Power Bank 5000 not only because its design was clearly targeted at iPhone Air users, but also because it is the thinnest (6mm) and lightest (98g) 5000 mAh power bank on the market, thanks to its relatively new high-energy-density silicon-carbon battery. When attached to the back of the Air it brings up the device’s weight to 263g in total, which is noticeably heavier than most other smartphones, but it also almost doubles the phone’s battery life. While the Xiaomi power bank can deliver 22.5W, it only does so via USB-C, and because it is not MagSafe -certified, it drops to 7.5W when charging the phone wirelessly (by snapping it on using MagSafe ), rather than the 15W that Qi2 phones get out of it. With the Air locked and inactive it takes about two to three hours to charge it to around 92%. It never reaches 100%, despite the power bank carrying considerably more capacity than the phone’s integrated battery, due to the inefficiency of wireless charging . Note: I’m aware that Google introduced MagSafe compatibility into its Pixel line with the Google Pixel 10 , however, there is no dedicated ecosystem targeting specifically the Pixel and its hardware design . For the narrow use case that I have personally been struggling to solve, which is “I need a single, lightweight, and highly reliable device to host all the closed-source corporate spyware I am forced to interact with, and I already have a primary GrapheneOS device for my actual life” , the iPhone Air seems like a very good option, at least ignoring the absurd price tag. It is light enough to carry in a Faraday bag inside my cabin luggage with me and it’s flat enough to occasionally bring it alongside a Pixel without making my pockets look like I pack big data. It appears to be reliable enough that I do not expect to repeat this exercise for at least another five to seven years, and it runs every attestation-dependent banking, travel, and near-future dystopian government app I might need it to run. On top of that, the mobile content-creation software story on iOS is, sadly, lightyears ahead of Android , as well as Windows and Linux . For anybody whose use case is “I want this device to be the primary, always-with-me phone that handles my nudes photography, my manifestos notes, my 4chaning web-browsing, and my doomscrolling actual life” , I cannot in good conscience recommend the Air , or any other iPhone , for exactly the same reasons I have been writing about for the past years . Apple is, with all due respect to its marketing department, a surveillance company . The fact that it chooses to surveil its users somewhat more politely than Google does is not, by itself, a reason to grant it custody of your private life. You cannot audit the OS, you cannot disable any hidden surveillance subsystem, and you most certainly cannot install a hardened replacement. The iPhone Air is a fascinating piece of engineering and a perfectly competent spyware appliance . It is however not, and will never be, my primary phone. Banking apps for several jurisdictions, most of which now require Google Play Integrity or equivalent attestation on Android and basically refuse to function on GrapheneOS without disabling the very protections that make GrapheneOS worth running in the first place. Apple Wallet for boarding passes and, in some jurisdictions, virtual VISA and MasterCards. Luckily I’m neither a citizen nor a resident of a country that imposes the absurdity of digital state-issued identifiers . Corporate apps that some clients might use and require, as well as privacy-invasive bs like WhatsApp , using throwaway phone numbers, in jurisdictions in which large parts of public life run on it . Travel apps (airlines, hotels, rental cars), most of which are technically available on GrapheneOS but which are also ill-behaved, ad-laden, and absolutely should not be on the same device as my personal data.

0 views
Kev Quirk 2 days ago

📝 2026-07-20 08:10: Yup. Goat-proofing the chicken door really worked a treat. FML. 🤦🏼‍♂️

Yup. Goat-proofing the chicken door really worked a treat. FML. 🤦🏼‍♂️ Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️ You can reply to this post by email , or leave a comment .

0 views