More from Armin Ronacher's Thoughts and Writings
For our last movie night we watched Princess Mononoke. I remembered loving that movie when I was younger, but watching it as an adult made me once again realize how Miyazaki has a way of expressing diverging sides without picking one. The film shows people, animals and spirits with legitimate and largely incompatible needs, and each faction is further engaged in infighting. A central arc of the story is Lady Eboshi’s Irontown, which gives people who were largely rejected by society work, protection and dignity. She gives shelter and work to those who have leprosy and to former sex workers. The mine and the weapon factory provide them with a livelihood, but they also destroy the forest around them. The forest’s inhabitants, in particular the boars, response choose war against the humans to defend themselves. Eboshi is not portrayed as a villain. She does real good for the people of Irontown, but also is an arms manufacturer who is destroying the forest around it. The film anchors around a character called Ashitaka, who has been condemned to death by an unfortunate encounter with a god that was turned into a demon after being fatally wounded by one of Eboshi’s guns. He doesn’t take sides, but he wants to understand and find the truth. Another character is San (whom they call Mononoke), a girl who was raised by wolves and, despite being human, considers herself part of the forest. This movie’s backdrop is human progress, and it reminded me so much of the challenges we are facing today with AI. AI is useful, empowering and consequential beyond the people who benefit from it. It’s similar to the iron in the story. Irontown gives the outcast purpose and power. There are people today who see themselves in an environment just like that: people who were never let in before and who can now build things that were out of reach. They are wielding AI to their benefit. But there are negative externalities. In Mononoke it’s not just the spirits and animals in the forest who bear the consequences, it’s also other people. Irontown produces guns, and its people are engaged in fights with other humans. There is conflict and power seeking everywhere. Another, unseen character is the power-hungry emperor, who wants the head of the forest spirit, a god, because he believes it will make him immortal. Eboshi is willing to support that cause, not because she thinks it’s right, but because she is at war with the forest’s gods who are preventing her expansion, so they have a common interest. But there really is no need for anyone to kill the forest spirit, in the same way there is no need for any one country to “win at AI”. What drives it is the fear of what happens if someone else wins first. And the emperor is willing to have a god killed for it. The people who help him with that desire, Eboshi included, don’t understand the chaos it will unleash. There it also shows the dangers of seeking overwhelming power without comprehension of how to control its consequences. The pursuit of power itself becomes destructive. In the end, the gods die, and what grows back is not the old forest anymore. Irontown is destroyed. Eboshi wants to rebuild it, and to build a better town this time. Ashitaka stays with the people of Irontown after his curse is lifted by the dying forest spirit. San cannot forgive the humans and stays with the wolves. In the end, nothing is truly resolved, but there is a truce that came at great cost. Ashitaka’s role in the movie is one of a neutral actor. He was wronged both by a spirit turned demon in the forest, who put a curse on him, and, indirectly, by Eboshi, who caused the spirit to turn evil. Yet he harbors no ill will towards either side. He sets out to “see with eyes unclouded by hate,” and in the course of the movie he is seen as an unaligned actor. He helps people on both sides, and stands in their way to prevent further conflict. He doesn’t feel like a pacifist, but he’s the closest to one there is. He’s a truth seeker in a changing world. Because he engages he’s seen as suspicious by both sides, and ends up shot by the people of Irontown when he tries to rescue San. I use AI every day and find it genuinely empowering. But I also recognize the pain it causes some, and the moral problems it poses. It’s genuine progress for humanity, but it comes at significant cost. And many of those costs will be carried by people who aren’t going to benefit from it. So it’s no surprise that AI feels like a threat to many today. Communities currently strongly align themselves with one side and fight against the other. The forst spirit did not have to die and the boars did not have to die in a senseless war. The question is not whether there will be iron, but what kind of Irontown we build with it. I want our conversation about AI to make room for nuance and genuine understanding, for us to look at it and each other with eyes unclouded by hate. We should take advantage of its real benefits, but also recognize the damage it can do, and the choices we still have about what we build and what we’re willing to sacrifice for it. I like to think there is a path for people with differing opinions can find a way to live alongside before losing something we can’t get back.
A few weeks ago I felt like it would be fun to see if I can make one of those cheap Chinese CarPlay dongles run something other than the stock firmware. The idea was that rather than just forwarding CarPlay, why not do something more interesting with them? They all work quite similarly: they act as bridges between your car and the phone. From there they deal with video and audio streams and pass some other data through. Most of them also bring up a custom UI for pairing and have a web interface that your phone can reach for updates. Long story short: I had a conversation with Fable and Sol via Pi about what could be done with such a dongle or whether I should use a Raspberry Pi instead if I wanted to do my own thing there. I figured it might be quite fun to run my own code while still allowing regular CarPlay to pass through. Through working with the LLM I learned about CatPlay, which is a Rust reimplementation of the CarPlay protocol that can run on Carlinkit devices. In particular, it can run on the Carlinkit Mini Ultra, which I figured would be easy enough to buy. I do have a few CarPlay adapters around, but I did not have that particular model, so I bought one on Amazon. Twenty-four hours later, I had a device in my hand that was branded as a Carlinkit Mini Ultra, but instead of being the Ingenic device that the original author used, it turned out to be something else. This is normally where the story would stop. However, it’s 2026. Armed with a bit of knowledge about how these systems work, I managed to have some fruitful discussions with Kimi K3 and Sol and figure out how flash the device and in turn, how to make CatPlay compile for that SoC. I guess that hacking these USB devices is not necessarily hard, but it’s laborious and you can easily end up bricking your devices. It also just sucks because sometimes you need to work with someone else’s code that does not itself run on your machine. In the past, I would abandon many such projects for lack of tenacity. But my clanker is tenacious. But so are all of our clankers. Some of the projects we’re now attempting are happening because of conversations we have with them. In this case I did not find or decide on CatPlay, the model did. It was not the only suggestion, but it became the best starting point after discarding others. And I discover this more and more. Particularly when we have solitary interactions with these models, some of us “independently” decide to work on similar projects. When I talked with an acquaintance about CarPlay he also mentioned recently that he decided to try something similar because he too wanted to see if he can get his own agent be hooked up with the car. And guess what: he too learned about the CarPlay hacking community, and that it’s an option, from the models and roughly around the same time. It really got me thinking about how this could create situations in which completely independent people end up building things they believe are their own ideas. Yet they were inspired or pushed towards doing something by a conversation with an LLM — a conversation that someone else also had. What if we took paths, because those were the paths that were more likely with current generation models? There is a running joke in the AI builder community right now that we’re all working on the same things, and in many ways it feels like we are. That might be because those things are obvious, or it might be partly because we all use the same models with the same capabilities. A few months ago, I first saw Lucas Meijer share the idea to make a model in Pi produce HTML reports rather than Markdown. I thought that was pretty unique. Except, well turns out the models are probably trained more and more for that (e.g. Claude Artifacts), and now it has become for many the default choice for sharing reports. How much of what we build comes from eliciting the same latent capabilities from the same models? Did the models make us prompt them that way? Was it because we shared ideas on Twitter and other communities that inspired us? Or is it all unrelated? There is something powerful and strange about how LLMs diffuse knowledge and capabilities, while perhaps also nudging us all simultaniously and independently toward building the same things.
A few weeks ago a paper was shared that showed how to extract reasoning traces from closed-weight models. Together with online discussions about tricking models into leaking them, it made me investigate it more out of curiosity. Twitter seems full of half-truths and confusion about how this works, so perhaps this helps some to understand what is happening. Hiding Traces Reasoning traces are usually hidden from us. We have lamented this, but mostly have to accept it. Open-weight models thankfully reveal them, and from their behavior you can see that their traces can be long and confusing. This is probably a good reason to separate them from what is normally shown to users. At minimum, UIs need to detect them. The industry has done a good job at making reasoning traces sound special and exotic, but they really are just text: the model is trained to emit its thinking into a scratchpad as part of its response, before its final answer. GPT-OSS’s Harmony response format makes this easy to see: <|channel|>analysis<|message|> I need to work this out ... <|end|><|start|>assistant<|channel|>final<|message|> The answer is ... <|return|> The markers are special tokens, but the reasoning between them uses “the same text” as the final answer (just that GPT chain-of-thought text sounds really funny). When the model samples the analysis channel token, a parser routes the following text into a separate stream exposed through the Responses API. For closed models, presumably a simple model redacts and summarizes it. Reasoning Effort How much budget goes to reasoning? Earlier APIs exposed reasoning token budgets, making it seem like a property of the sampling process. In reality, reasoning effort is baked into the system prompt. GPT-OSS puts this into the system prompt: Reasoning: low That’s it. Training produces the resulting behavior, such as emitting the token sequence that switches to the analysis channel. This also explains why changing the effort invalidates the KV cache. I think closed GPT models call reasoning effort “juice,” since you can ask most models how much juice they have. In DwarfStar for DeepSeek with max reasoning this is added to the system prompt: Reasoning Effort: Absolute maximum with no shortcuts permitted. You MUST be very thorough in your thinking and comprehensively decompose the problem to resolve the root cause, rigorously stress-testing your logic against all potential paths, edge cases, and adversarial scenarios. Don’t Think The destination of reasoning tokens is therefore a learned convention: the model is trained to keep scratch work out of the final channel. Trick it into thinking it is in that channel and it may leak tokens. We have even seen older models, when thinking is disabled, reason into the bash tool and echo their thoughts to /dev/null. So in some sense the only “special” behavior for some models is not to think. That at times is done by “mechanically” removing the model’s usual ways to think. In DwarfStar, disabled thinking uses the prefill </think>, while enabled thinking uses <think>, which are the tokens that close and start thinking. GPT-OSS doesn’t prefill but lets the model decide either way on its own. But presumably, some inference APIs prefill the opening token when reasoning is enabled, so the model never samples it itself and might prevent the sampling of the reasoning token when disabled since it can be trivially detected. This may explain why a custom think tool can trick models into putting some reasoning where it should not go — but only when native reasoning is disabled. Fun fact: this blog post triggered safey checks Hilariously enough I was unable to use GPT 5.6 terra for spell and grammar checking on this blog post because of safety filters. Had to switch to Kimi.
A very strange Pi issue sent me down a rabbit hole over the last two days. The short version is that newer Claude models sometimes call Pi’s edit tool with extra, invented fields in the nested edits[] array. And not Haiku or some small model: Opus 4.8. The edit itself is usually correct but the arguments do not match the schema as the model invents made-up keys and Pi thus rejects the tool call and asks to try again. That alone is not too surprising as models emit malformed tool calls sometimes. Particularly small ones. What surprised me is that this is getting worse with newer Anthropic models as both Opus 4.8 and Sonnet 5 show it but none of the older models. In other words, the SOTA models of the family are worse at this specific tool schema than their older siblings. In case you are curious about Fable: I intentionally did not test it because I was not sure if the classifiers they are running might downgrade me to Opus silently. Tool Calls Are Text If you have not spent too much time looking at LLM tool calling internals, the important thing to understand is that tool calls are not magic and use some rather crude in-band signalling. The model receives a transcript, a system prompt and a list of available tools. The server munches that into a large prompt with special marker tokens. Because the model was trained and reinforced on examples of that format, at some point during generation it emits something that the API or client interprets as “call this tool with these arguments”. For a file edit tool, the intended invocation payload might say something like this: { "path": "some/file.py", "edits": [ { "oldText": "text to replace", "newText": "replacement text" } ] } A harness then validates the arguments, performs the edit, and feeds the result back into the model. If validation fails, the model sees an error and usually tries again. How exactly that formatting happens is not known for the Anthropic models, but some people have gotten out “ANTML” markers and they at times do leak also into public communications. To the best of my knowledge, the call above would come out serialized like this from the model: <antml:function_calls> <antml:invoke name="edit"> <antml:parameter name="path">some/file.py</antml:parameter> <antml:parameter name="edits"> [ { "oldText": "text to replace", "newText": "replacement text" } ] </antml:parameter> </antml:invoke> </antml:function_calls> An important thing to note here is that this thing, while looking like XML, is not really XML. It’s just a thing they found convenient to tokenize and train on. The other thing to note is that a basic top-level string parameter appears in-line whereas an array of objects is implemented via JSON serialization. While I’m not entirely sure that this is how it works, there are some indications that this is not too far off. This will become relevant later. There are two very different ways to make the model produce a structure like this: You can ask the model to produce valid JSON matching a schema and then validate it afterwards. You can constrain the sampler so that invalid JSON, or even invalid schema shapes, cannot be sampled in the first place. The second approach is what people usually refer to as grammar-aware or constrained decoding. The sampler masks out tokens that would violate the grammar. If the model is currently inside a JSON object and the schema says only oldText and newText are allowed, the sampler can prevent it from emitting "in_file" or "type". Grammar-aware decoding can be used both to constrain something to be syntactically valid JSON and also to enforce specific enum values or keys. Without any form of constraints the model is merely following a learned convention. The Failure Pi’s edit tool supports multiple exact string replacements in one call. That is why the arguments contain an edits array. In the failing cases the model produces entries like this: { "oldText": "...", "newText": "...", "requireUnique": true } or this: { "oldText": "...", "newText": "...", "oldText2": "", "newText2": "" } Across repeated trials I saw a whole zoo of invented trailing keys: type, id, kind, unique, requireUnique, matchCase, in_file, forceMatchCount, children, notes, cost, oldText2, newText2, oldText_2, newText_2, and even an event.0.additionalProperties key inside the edit object itself. The most annoying part is that the actual oldText and newText payloads were byte-correct in the invalid calls I inspected. The model had in fact produced the right invocation but then added nonsense at the end of the object. The failure is also heavily context-dependent. A fresh single-turn prompt like “edit this file” did not reproduce it at all for me. An agentic history where the model had read files, diagnosed a problem and then composed a multi-line edit could reproduce it. And more annoyingly, not all transcripts will show that behavior. In fact, I needed Petr Baudis‘s transcripts to reproduce this for me at all! In that user’s session continuing the session caused Opus 4.8 to fail around 20% of the time. Stripping thinking blocks from history reduced the failure rate by half. Turning on strict tool invocation eliminated it in my runs. Why It’s Getting Worse My strongest hypothesis is that this is not random deterioration but a training artifact. When older Anthropic models were trained, they were trained on some tools (some of which were documented). But that training did not yet have a user-shipped harness like Claude Code as the obvious target. Modern Anthropic models are most likely different because their post-training includes Claude Code or a harness that looks very similar. The model learns what a successful tool call looks like in that environment. It also learns what mistakes are tolerated by that environment. Claude Code’s own tools are comparatively flat. The ordinary edit tool is not Pi’s nested edits[] shape; it is closer to file_path, old_string, new_string, and an optional flag (replace_all). Looking at Claude Code’s client is very instructive: it contains retry paths for malformed tool use, parameter aliases, type coercions, Unicode repairs and filtering of unknown keys. In other words, Anthropic’s own client appears to expect and accept a fair amount of slop and repairs it, mostly silently. If reinforcement learning happens in a harness like that, or a simulation of one, then slightly malformed tool calls can still complete the task and receive reward. The harness fully absorbs the error and there is little gradient against inventing an alias, adding a stray field or using a nearby parameter name. Worse, the model may become very strongly adapted to the canonical Claude Code edit tool shape. A different harness can present a tool with the same semantic intent but a different schema. Such a tool can increasingly be off-distribution. The better-trained model might actually fight you harder because its prior is stronger. This is not too surprising, but it is a change from how this was a few months ago. When Opus 4.5 launched, it adapted to other edit tools exceptionally well. In fact, I was pretty convinced that we’re on a good path where the models are more likely to adapt to any sort of tool shape that comes around for as long as the instructions are good. Now I’m somewhat worried about the track we’re on here. Alternative tool schemas might not just be unfamiliar. They might be implicitly punished by post-training that optimizes for one particular, forgiving tool ecology. And that ecology is not documented. While there is a text editor tool that is documented, you will see that this format is in fact not followed by Claude Code. What Claude Code does internally (which is a closed-source harness) is hidden from you. The Slop Harness Claude Code is obviously closed-source but we can look at the minified code and get some idea of what it does. And honestly, it’s very forgiving of incoming data. For a start, Claude Code checks the model’s visible text for leaked <invoke markup. It also emits some telemetry when that happens and then it has its own state machine to retry such bad calls by pushing back to the model. It has explicit Unicode escape repair which fixes broken \uXXXX sequences and lone surrogates in string values. It also has per-tool aliases for parameters. For instance, Edit accepts old_str (presumably from the times when the models were trained on the officially documented text editor tool), the newer old_string from the schema, new_str/new_string, path as an alias for file_path, and some more. It also silently filters out unexpected keys and it does not use strict mode either. The issue with strict mode is that Anthropic applies complexity limits to the tool definitions that cause API requests to fail, so presumably that’s why Claude Code does not attempt to use it. Strictness Will this problem be with us in other harnesses too? One huge issue with Anthropic is that the models are completely closed, and so is the harness. Codex models are also closed, but at least the harness is not. We also have gpt-oss which is at least a bit interesting. The models are explicitly trained to use OpenAI’s harmony response format and there is a lot of documentation that at least tells us how OpenAI people think about this. Harmony makes channels and tool-call content types part of the prompt format. A function call can look like this: <|start|>assistant<|channel|>commentary to=functions.get_weather <|constrain|>json<|message|>{"location":"San Francisco"}<|call|> The important bit is <|constrain|>json. The model can express in-band that this message body is JSON, and an inference stack can use that boundary to switch into JSON-constrained sampling for the body of the tool call. Presumably a bit of this also happens in Anthropic’s models, at least in strict mode I would imagine. The marker in harmony helps the sampler to detect when it needs to sample with a specific grammar, and because it is part of the transcript, it makes that rather easy to do. For hosted GPT models, there is also an option to provide a LARK grammar for custom tools that need to adhere to something like this. Anthropic appears different from that, though maybe not entirely. If an array of objects is represented as JSON, as it appears to be, then the model has to write JSON inside the tool parameter. There is probably basic grammar-constrained sampling going on, and that may partly explain the extra keys. For a nested array parameter, that JSON includes escaped multi-line file content inside string literals, inside one tag. The unexpected, made-up keys appear exactly at the highest-entropy point of that task: after closing a several-hundred-token escaped newText string, where the model must decide } vs , "...". As strict mode in Anthropic appears to fix this, I presume that on the server side they are refusing to sample a key that is not permitted by the JSON schema structure. That would also explain why they have limits to the complexity of the tool definitions when strict mode is enabled. So far, the Codex models I tested did not show this type of regression. I tested all available ones except 5.6, which I do not have access to yet. What This Means For Harnesses The uncomfortable lesson is that tool schemas are not neutral, at least not on Anthropic models. We like to pretend that a schema is an abstract contract and the model is a general reasoner that will follow it, but that might no longer be the case for some of the tools. Tool schemas are somewhere in the distribution and some shapes are close to what the model saw during post-training and some are far away. Some are easy for the provider’s hidden encoding (e.g. top-level attributes in ANTML), whereas some require the model to write large escaped JSON objects inside nested arrays after long multiline strings. The model may be smart enough to understand the schema and still be bad at sampling the exact shape under pressure. If this type of model behavior continues, I wonder what the implications for harnesses are. Obviously one could turn on strict sampling in Anthropic and the problem should go away. On the other hand, that the model has this behavior shows the impact that reinforcement learning has on them. Fighting that prior is probably futile if you want to get the best model performance. Right now the reality is that Claude Code is not open source and we cannot really know what they are doing in their RL environments either. We cannot assume Claude-Code-trained behavior will transfer cleanly to your tools unless they are a close match. The more post-training happens inside one dominant harness, the more every other harness will have to inherit its quirks. I used to be more skeptical of strict grammar-constrained tool invocation because constrained decoding can have quality tradeoffs. I still think that can be true in general, but this bug moved my priors significantly. If the newest models get better at solving the task while getting worse at faithfully emitting an alternative tool schema, then the harness needs stronger guarantees somewhere. If you want to find out more, or you want to discuss this, consider reading the issue on the Pi tracker.
More in AI
I really want a lot of venture capital investors to work on their self-esteem. After a few decades of supporting and mentoring New York City’s tech community, I hope I’m credible when I say I care a lot about how it thrives. So one of the most disappointing—and frankly surprising—things I’ve seen lately is how many investors in the greatest city in the world have been lowering themselves, sucking up for approval from a cohort of Silicon Valley tycoons who hate our city, hate our values, and want us to fail. I’m furious because there are so many good people and good ideas here that deserve to thrive, and aren’t getting the chance. Why would anyone sit by while outsiders put our community down, only to let those same outsiders profit off us when we succeed anyway? In fairness, I’m not talking about all of our city’s investors. Some are content to keep their heads down and hope the worst of the West Coast doesn’t notice them. But imagine if our other civic institutions worked this way: the Knicks timidly stepping onto the court and standing back while opponents charge the rim, or the Liberty letting the other team fire off shots unchallenged. This is not the New York City I know. What real New Yorker, when faced with a taxi cab headed toward them in a crosswalk, would say, “Oh, sorry, I was going to be walking here, but you go right ahead and run me over, good sir!” It’s pathetic, and it’s bad for business. Our city is watching, and our kids are too. HQ Zero I’ve been lucky enough to watch brilliant friends build innovative businesses here, having each other’s backs and catalyzing a community that lifted up the city we all love. And then, over and over, we watched our lawmakers line up to give billions in handouts to West Coast tycoons who’d already won the game. Even when the community stopped those giveaways, the companies still hired just as many people here as they’d promised—because people want to work in New York City. Our tech community's own data shows that, while the Bay Area lost tech jobs over the last 5 years, we've grown by 23%. We never needed to bribe these guys in the first place. (Unsurprisingly, many of the same people who once demanded access to New York taxpayers’ pockets started trashing our city and its most vulnerable residents the moment the freebies dried up.) The lesson is simple, for the public sector and private investors alike: we don’t need to buy the love of people who hate New York, or act as if we’re inferior and desperate to import an economy from elsewhere. We don’t do that shit here. We don’t need to be thirsty. We can invest in the people who already love this city enough to build the future here. We are, you may learn, second to none. Fortunately, we’ve replaced the timid, backwards-looking leadership of the past with people who believe in our ability to lead, build, and invent a better future. It’s no surprise that New Yorkers are more optimistic than they’ve been in decades, or that we have the lowest crime in recorded history—nor that the people who hate our city are lying about all of it. The very same tycoons who felt entitled to taxpayer handouts now feel entitled to treat our investors as feeder funds for their own goals. There is no future in funneling deals to firms trying to undermine our entire civic ecosystem. Building value, having values I’m still committed to the radical social ethos that you should be able to build tech companies worth hundreds of millions of dollars, that founders and employees can get fabulously wealthy while workers are paid fairly, that investors earn a solid return, and that everybody pays an appropriate tax rate to the city that made it all possible. I don’t care if it makes me a radical to think those opportunities shouldn’t be hoarded by the same three or four predatory jerks who can’t stop trashing New York. It’s no secret that the rise of authoritarianism and bald-faced bigotry among Silicon Valley investors has led them to demonize our city. What’s almost too much to bear is watching people I’ve respected in New York look the other way while those leaders embrace rank misogyny, blatant antisemitism, unapologetic Islamophobia, and profound racism—so virulent that the most powerful venture capital firm in the world hired a partner on the basis that he strangled an unarmed Black man to death. I’m grateful that many of you tell me privately that you object and still hold onto your moral compass, which makes it all the more heartbreaking to watch so many go silent publicly. Where is your self-respect? Because I’ll be honest: they are laughing at you for debasing yourselves in front of them, and they enjoy shitting on the city you call home. You should do work you’re proud of, that you feel good telling your family about, and that you’re excited to share with your community. You should also do the math. A tiny handful of firms control the vast majority of late-stage funds, and you are not going to differentiate yourself by being a mindless feeder fund for the same 10 cancer capital firms as everyone else. If your only edge is competing on who can kiss Andreessen’s ass the most, you’re already fucked, kids. Look at how they already have to tap-dance—calling things “super intelligence” instead of “artificial intelligence” just to prove their fealty. How long until you’re asked to publicly rename your work, or tell a big lie about your city, just to stay in the room? I’ve heard too many people in this town claim they don’t have any power, that their only job is returning capital to LPs. All you have to do is the simplest thing in the world: refuse to play along. By contrast, if you bet on this wonderful community, connect to the next generation of innovators, and fight for the future instead of against it, there is limitless opportunity here. If you have to put it in a way your LPs can understand, explain that there is huge alpha in going the way that a16z is not. Call it “Anti-authoritarian Dynamism”. Explain that you’re going to strangle their deal flow, since founders of color and next-gen innovators don’t want to talk to the firms who hate New York City and hire killers. Tell them you’re choking off the supply chain of capital to the office where Daniel Penny works. Side with the founders, not the funders Just in case you don’t already know: Zohran Mamdani is your best friend. He wants the city to win, and our businesses to thrive. And those West Coast VCs who act deranged when you mention his name? They want your city destroyed, and when it's not, they lie and say that it already has been destroyed. Pick the side of your neighbors and your community, and speak up for the founders and entrepreneurs building the opportunities you want to be part of. Just as importantly, speak up for yourself. It’s not viable in the long term for every outcome—and the small number of possible exits for your portfolio—to be controlled by the same handful of gatekeepers. I used to love helping friends turn cool new products into companies that provided good jobs; now that’s virtually impossible because the scale has gotten so absurd, and so few players decide who gets to participate. When I talk to people who are still early in their tech careers, the only names they know in the investor world are the usual suspects — not yours. They’ve never heard of your firms, of many of New York's most thoughtful and interesting and supportive investors, and they’re downright skeptical when I tell them to work with NYC-based investors instead of making a trip to Sand Hill Road. That all changes the moment New York’s tech leaders put their power behind an alternative narrative. Simply saying “we are here, we exist, and we are not a satellite of the same tired agenda you’ve been hearing from Silicon Valley for years” would be hugely valuable for the entire New York City tech ecosystem. It's going to be especially resonant after the entire country just picked a political path that looks a lot like New York City's values — and is based on rejecting Big Tech's values. It would also, I expect, do wonders for your soul after years of enduring the quiet indignities of watching some horrid people chip away at your self-esteem. Now, I know most of you aren’t inclined to go to war. That’s fine — you can still be nice. Jalen Brunson is really nice! Karl-Anthony Towns is really nice! Sabrina Ionescu is nice! But they really like to win, and they don’t take shit from anyone. You have to decide if you want to win, or if you want to get bullied on the playground by the people who actually have their heads in the game. As a repeat founder who spends my time with makers — both the next generation of creators, and the people who’ve built great companies before them — I know where my loyalty lies. Those of us who build things know who we are. Those of us who love New York City are having one of the great moments of the modern era. Do you know who you are? Are you going to join us?
[Everyone is doing guest posts these days, so here’s one about the Weil conjectures from (in alphabetical order) Bin Dong, Nailin Guan, Jiedong Jiang, Ruochuan Liu, Christian Merten, Xiangyu Pan, Tingxiao Shi, Bin Wu, Edison Xie and Wei Yang] We … Continue reading →
20 years ago to this day, I started my new technical blog. I'd had a personal one for some time, but most of the stuff that happened there had already migrated to social media. I wanted somewhere to post the things that would only be of interest to my techier friends, and maybe of some use to anyone else that came across it. Things have changed a bit, but they've stayed the same in some ways. Earlier this year I finished my 48-part (!) LLM from scratch series, but it had predecessors -- the third post I made here was part one of a 13-part series where I worked through setting up automated backups for my homelab NAS, and then later on I spent a few months building a reverse proxy in C, not to mention the eight-month, ten-post series on fine-tuning LLMs. It does seem like there's some value to putting all of this online. I rarely check my logs and referrers, but people do still seem to be arriving here having searched for stuff that I've written about, and every now and then there's a kind "thanks for this!" comment left on an old post where I explained something I'd just learned. I wrote a bit more about the blog's history last year, and came to the conclusion that the best posts -- both for me to write, and as far as I could tell for other people to read -- were the ones where I wrote up a project that I'd been working on. I blogged about that in more detail, and it seemed to strike a chord on Hacker News; I think it still holds. Recently, Sean Goedecke suggested that the best blog posts are those where you write about things that you're in the process of learning, and I agree. You learn more than you would if you didn't write it up, and because things are fresh in your mind, you may well write more clearly about it than an actual expert in the subject might have done. Anyway, I'm going to carry on blogging. I'm working on my biggest LLM-related project so far (dozens of training runs, so my study aircon is getting quite the workout even with the weather turning colder), and look forward to posting about it later on this month. I hope it's at least as fun to read as it is to write!
Announcing STABL: Societal Transformation and AI Bottlenecks Lab