I really like what exe.dev is doing. And their philosophy of how cloud services could work is amazing. I have a monthly subscription and it's really cool to just vibe code a little website with Shelley and have it running in minutes. I feel like I have so much fun using their service, and spend so much less time thinking about what things will cost, or what cloud service to use. It's just so much simpler and the friction is so much less compared to other cloud services.
> But our VMs start fast, so fast that even if we created the DNS entries before creating the VM, our users still had to sit around waiting for DNS to propagate, which occasionally took minutes, not seconds.
To my (limited) understanding, this is not a good idea, and is an unfixable problem from the server side. Companies, VPNs or ISPs or routers, often use their own DNS servers, and those can have caching logic, which means it doesn't matter how fast your own DNS implementation is, as the users lookup request wont hit your DNS server, it'll hit an intermediate cache.
A compiler is an algorithm and Claude isn't*. A compiler almost never produces a wrong output, even when compiling an extremely complicated program. But a compiler must be clearly defined and is limited to input/commands it's defined for. A compiler will "correctly" process input into unintuitive output, but that's not always what the user intended (e.g. omitting large sections of code that are undefined behavior). Claude makes mistakes, but can process any input/command expressible in training data, and has more potential to infer when something is unintentional.
Tools like Claude are great at building algorithms, then tests to verify them. The algorithms they build aren't just compilers, but any software that can be verified. Even though Claude may not be a compiler, it has the potential to (at least if it improves) create production-grade software that can be verified, like other compilers. But maybe not good UX without human input (expanded to any subjective experience, like video games).
* Not a "source language to target language" deductive algorithm. Technically Claude is an algorithm to predict the next token, but acting as a compiler or anything else it's an inductive heuristic, because it guesses (https://stackoverflow.com/q/2334225)
> I read a vanishingly small amount of the actual code.
This sentiment kind of saddens me. I'm all for burning tokens to write throwaway code just to prototype a solution, but I don't get not reading (or at least familiarizing yourself with) the code that you will deploy to prod.
And claude isnt a replacement for the chain of humans, you dont know what you dont know, thats why we have a person in a role to gatekeep each step.
Anyone using claude can see it misses steps that an engineer wouldnt, it can make bad choices that a sysadmin wouldnt, it can pick the wrong order a project manager wouldnt, it can pick wrong cost models that a bean counter wouldnt, etc etc etc
But, I'm pretending it is and living with those mistakes.
> I’d say that, in all the ways that matter, I understand the code. Sure, if I had to hand-edit it now, there’d be a serious learning curve. But I won't have to.
Famous last words, but point is taken.
The non deterministic nature of an llm breaks the metaphor that they are like a compiler.
However, it’s not foreign to compilers to receive feedback from the running program (PGOs), so there are still parallels to the feedback we provide LLMs that guide their “optimization”.
I think even calling LLMs a non-deterministic compiler isn’t accurate either so ultimately I agree the metaphor doesn’t quite work.
I do think LLMs are like compilers in terms of how they changed how we build programs from a historical context. But that’s about it.
> Claude wasn’t just a compiler here. I never handed off a task and let an agent make a bunch of decisions in order to reduce it to practice.
> I’d say that, in all the ways that matter, I understand the code.
I think the dissonance here is really important, and not a bad thing at all. A lot of the decision _were_ handed off the the AI, but they weren't the decisions the author cared about. This is a big selling point of AI! If something is doable with a computer, it’ll figure it out. 30 minutes and 200m tokens later, it’ll take any idea and declare “the feature is fully implemented.”
The hard part is figuring out where to inject that friction, so you can see where it's making decisions for you that matter. The author approached this by incrementally building the thing, reviewing and poking and prodding at every step. A week of attention following a bunch of design discussions is fast, but that's still not trivially cheap.
I want to see us talk more about the decision exhaust of agents, because the better the models get, the more decisions we'll want them to make.
LLM-is-a-compiler is indeed a simplistic approach. I wrote a rebuttal to the yesterday's Cursor post, may reuse it here https://replicated.live/blog/follow-up
The idea that a 835-page spec "just exists" and we run an LLM to implement it is completely flawed. Specs do not appear out of nowhere, they co-evolve with the code. If you have the code, why do you want to generate it again?
Good software is made as a product of numerous feedback loops and LLMs let you operate those loops faster. They do not supplement the entire process though.
In the end, a good product is a barrel of distilled feedback.
Claude is more like a Probabilistic Turing Machine. [0] It's correctness isn't deterministic but rather a distribution. It is predictable.
There are lots of places in computer science that determinism isn't necessarily the best.
- UDP video calls let packets vanish or arrive corrupted, because waiting for retransmissions would freeze the picture.
- Stochastic gradient descent picks a random mini-batch of training data and treats it as the whole dataset, because computing the true gradient on every step would make training infeasible.
- Speculative execution in modern CPUs guesses which branch a program will take and rolls back when wrong, because waiting for the real answer would leave half the silicon idle.
What we want is something like a Las Vegas algorithm, a probabilistic machine with a cheap verifier.
Specs might become one solution for coping with the need to review increased volume of code. A spec is a higher level of abstraction than code, which is a higher level of abstraction than machine code. The industry made the transition to higher-level once, paradigm is changing so it might happen again.
The workflow I imagine is either deriving specs from the conversation or reverse engineering the code to spec, review and edit the spec which should be tighter and much more compressed, then deterministically compile to code. Of course we don't want to be spec-first only, that would be going back waterfall, but doing iterations back and forth.
Now, Claude is not a compiler because it is closed and non-deterministic (they do opaque processing on server, hiding reasoning tokens), but LLMs might be. We refer to a piece of code from npm/pip by name to get some code by downloading it. We then have lockfiles with hashes to ensure integrity. Currently we are vibing it, but in the future we could refer to a piece of code by prompt/spec and getting the code by inferring it. To ensure integrity, the lockfile would be hashes of open weights and inference code (and ironing out implementation details like non-determinism due to GPU scheduling, etc.).
I still think it is (in the source-code generating mode) a compiler, just like LiquidHaskell is. (I haven't used LH but it essentially can automatically supply functions based on the type conditions you specify.)
In my view, reasoning LLMs have learned a large number of close to true sentences of "logic" in natural language. These rules are not consistent (unlike typing rules of LH that allow creation of provably correct programs), but they work in practice better than LH. Essentially, they represent an unsound formal specification of natural language, together with many useful (almost)tautologies that helps solving constraint problems (just like LH does, but again unlike LLM, provably correctly).
LLMs proved that human language can be formalized reasonably close to soundness. I believe we can have a sound formalization of human language, and that kind of formal language will be once superior to LLMs.
It will also not be as complicated as LLMs and require only fraction of compute to use.
> By the time I was ready to build a keeper, I had accumulated a scar-tissue document that was empirically sufficient to guide an agent through most of the important decisions, at every layer, ranging from high level goals through architecture down to the occasional low level detail, such as the exact shape of the data type for load-bearing concurrent caches.
I've heard something along the lines of "Claude is like a compiler: source code is the new object code, you don't look at that anymore" many times.
And I don't really think this is true. Compilers are usually deterministic, and whilst we can find edge cases, it's nothing like an AI agent writing all the code for you.
I think you have two choices, given the Claude is a code generator and not a compiler: (a) you review most or all of code to make sure it makes sense, or (b) you trust but verify via a strong test suite, potentially also created by Claude.
The problem with (a) is that you lose a lot of the speed-up. The problem with (b) is that you have no human oversight and the code may be incomplete, badly designed, or plain wrong.
Currently we review all code because correctness is extremely important to what we do, but that comes at a cost.
I don't know what the answer is here, in general. Does trust build over time? Do the models just get so good we can trust them to make zero mistakes?
Part of the value of LLMs and humans is nondeterminism. Pair nondeterministic output with strictly verified results (proper tests) and you can create a useful working system.
Humans can't build a system perfectly, and agents definitely can't. And agents (like humans) will build a different system every time even with the same prompt. Even if it's just trivial differences like array vs linked-list, there are still differences.
The value in having executable code is that it won't change its behavior unless you deliberately modify it. I don't think there are any shortcuts. Models will get smarter and smarter and make fewer mistakes, but you'll still want to produce real source code to execute because it's consistent (you can sell it as a product, set it and forget it, etc.), and most importantly:
running real code is orders of magnitude faster than having an AI either run the process "manually", or have it write the code out multiple times.
> I’d say that, in all the ways that matter, I understand the code. Sure, if I had to hand-edit it now, there’d be a serious learning curve. But I won't have to. And more importantly, I can reason about the system, share perspectives with my colleagues, and guide agents on future work.
If there's a serious learning curve to editing code then you don't understand the code. We used to call that 'on-boarding' when you brought a new engineer on the team as they got up to speed as to how the codebase worked.
This seems to be grasping for analogies to make sense of the work this person was doing.
A compiler does a lot more than source code translation.
There are specifications that tell us the de jure specifications of the language, if there is one, and then we have to recognize the de facto implementations of said language. The often disagree and leave much on the table. Some times on purpose, such as implementation details, and other times by omission.
Users of this compiler expect a deterministic compilation of the source text into the target code but it’s rarely 1:1. There are optimization passes, inlining, barriers, etc.
And then there are the run-time effects of executing a program!
I think the analogy gets a little weak because natural language is not a precise enough language to specify discrete systems.
What it sounds like the author is doing is bypassing decision points with other people and delaying making decisions themselves until the LLM agent forces them to? Which is a fine approach but I don’t think the analogy with a compiler is necessary.
People seem to have a hard enough time understanding branch prediction and thread barriers.
39 comments
[ 1.5 ms ] story [ 49.4 ms ] thread1) The construction of the Empire State Building was particularly effective due to the depth of human-to-human collaboration.
2) Isn't it great that we can burn a bunch of dinosaur blood to convince ourselves that we don't need other humans?
To my (limited) understanding, this is not a good idea, and is an unfixable problem from the server side. Companies, VPNs or ISPs or routers, often use their own DNS servers, and those can have caching logic, which means it doesn't matter how fast your own DNS implementation is, as the users lookup request wont hit your DNS server, it'll hit an intermediate cache.
It even has just-in-time compilation: it can directly follow a spec and generate small snippets live.
I'm pretty sure we'll soon see services (admittedly highly inefficient) built on Claude-as-a-backend.
Tools like Claude are great at building algorithms, then tests to verify them. The algorithms they build aren't just compilers, but any software that can be verified. Even though Claude may not be a compiler, it has the potential to (at least if it improves) create production-grade software that can be verified, like other compilers. But maybe not good UX without human input (expanded to any subjective experience, like video games).
* Not a "source language to target language" deductive algorithm. Technically Claude is an algorithm to predict the next token, but acting as a compiler or anything else it's an inductive heuristic, because it guesses (https://stackoverflow.com/q/2334225)
This sentiment kind of saddens me. I'm all for burning tokens to write throwaway code just to prototype a solution, but I don't get not reading (or at least familiarizing yourself with) the code that you will deploy to prod.
Anyone using claude can see it misses steps that an engineer wouldnt, it can make bad choices that a sysadmin wouldnt, it can pick the wrong order a project manager wouldnt, it can pick wrong cost models that a bean counter wouldnt, etc etc etc
But, I'm pretending it is and living with those mistakes.
Famous last words, but point is taken.
The non deterministic nature of an llm breaks the metaphor that they are like a compiler.
However, it’s not foreign to compilers to receive feedback from the running program (PGOs), so there are still parallels to the feedback we provide LLMs that guide their “optimization”.
I think even calling LLMs a non-deterministic compiler isn’t accurate either so ultimately I agree the metaphor doesn’t quite work.
I do think LLMs are like compilers in terms of how they changed how we build programs from a historical context. But that’s about it.
> I’d say that, in all the ways that matter, I understand the code.
I think the dissonance here is really important, and not a bad thing at all. A lot of the decision _were_ handed off the the AI, but they weren't the decisions the author cared about. This is a big selling point of AI! If something is doable with a computer, it’ll figure it out. 30 minutes and 200m tokens later, it’ll take any idea and declare “the feature is fully implemented.”
The hard part is figuring out where to inject that friction, so you can see where it's making decisions for you that matter. The author approached this by incrementally building the thing, reviewing and poking and prodding at every step. A week of attention following a bunch of design discussions is fast, but that's still not trivially cheap.
I want to see us talk more about the decision exhaust of agents, because the better the models get, the more decisions we'll want them to make.
I wrote a bit more here: https://tern.sh/blog/compiler-never-says-no/
The idea that a 835-page spec "just exists" and we run an LLM to implement it is completely flawed. Specs do not appear out of nowhere, they co-evolve with the code. If you have the code, why do you want to generate it again?
Good software is made as a product of numerous feedback loops and LLMs let you operate those loops faster. They do not supplement the entire process though.
In the end, a good product is a barrel of distilled feedback.
There are lots of places in computer science that determinism isn't necessarily the best.
- UDP video calls let packets vanish or arrive corrupted, because waiting for retransmissions would freeze the picture.
- Stochastic gradient descent picks a random mini-batch of training data and treats it as the whole dataset, because computing the true gradient on every step would make training infeasible.
- Speculative execution in modern CPUs guesses which branch a program will take and rolls back when wrong, because waiting for the real answer would leave half the silicon idle.
What we want is something like a Las Vegas algorithm, a probabilistic machine with a cheap verifier.
[0] https://en.wikipedia.org/wiki/Probabilistic_Turing_machine
The workflow I imagine is either deriving specs from the conversation or reverse engineering the code to spec, review and edit the spec which should be tighter and much more compressed, then deterministically compile to code. Of course we don't want to be spec-first only, that would be going back waterfall, but doing iterations back and forth.
Now, Claude is not a compiler because it is closed and non-deterministic (they do opaque processing on server, hiding reasoning tokens), but LLMs might be. We refer to a piece of code from npm/pip by name to get some code by downloading it. We then have lockfiles with hashes to ensure integrity. Currently we are vibing it, but in the future we could refer to a piece of code by prompt/spec and getting the code by inferring it. To ensure integrity, the lockfile would be hashes of open weights and inference code (and ironing out implementation details like non-determinism due to GPU scheduling, etc.).
In my view, reasoning LLMs have learned a large number of close to true sentences of "logic" in natural language. These rules are not consistent (unlike typing rules of LH that allow creation of provably correct programs), but they work in practice better than LH. Essentially, they represent an unsound formal specification of natural language, together with many useful (almost)tautologies that helps solving constraint problems (just like LH does, but again unlike LLM, provably correctly).
LLMs proved that human language can be formalized reasonably close to soundness. I believe we can have a sound formalization of human language, and that kind of formal language will be once superior to LLMs.
It will also not be as complicated as LLMs and require only fraction of compute to use.
Waterfall is dead, long live waterfall!
And I don't really think this is true. Compilers are usually deterministic, and whilst we can find edge cases, it's nothing like an AI agent writing all the code for you.
I think you have two choices, given the Claude is a code generator and not a compiler: (a) you review most or all of code to make sure it makes sense, or (b) you trust but verify via a strong test suite, potentially also created by Claude.
The problem with (a) is that you lose a lot of the speed-up. The problem with (b) is that you have no human oversight and the code may be incomplete, badly designed, or plain wrong.
Currently we review all code because correctness is extremely important to what we do, but that comes at a cost.
I don't know what the answer is here, in general. Does trust build over time? Do the models just get so good we can trust them to make zero mistakes?
Humans can't build a system perfectly, and agents definitely can't. And agents (like humans) will build a different system every time even with the same prompt. Even if it's just trivial differences like array vs linked-list, there are still differences.
The value in having executable code is that it won't change its behavior unless you deliberately modify it. I don't think there are any shortcuts. Models will get smarter and smarter and make fewer mistakes, but you'll still want to produce real source code to execute because it's consistent (you can sell it as a product, set it and forget it, etc.), and most importantly:
running real code is orders of magnitude faster than having an AI either run the process "manually", or have it write the code out multiple times.
What do you think happens in terms of testing/reviewing going forward? I'd really appreciate your thoughts on that.
If there's a serious learning curve to editing code then you don't understand the code. We used to call that 'on-boarding' when you brought a new engineer on the team as they got up to speed as to how the codebase worked.
A compiler does a lot more than source code translation.
There are specifications that tell us the de jure specifications of the language, if there is one, and then we have to recognize the de facto implementations of said language. The often disagree and leave much on the table. Some times on purpose, such as implementation details, and other times by omission.
Users of this compiler expect a deterministic compilation of the source text into the target code but it’s rarely 1:1. There are optimization passes, inlining, barriers, etc.
And then there are the run-time effects of executing a program!
I think the analogy gets a little weak because natural language is not a precise enough language to specify discrete systems.
What it sounds like the author is doing is bypassing decision points with other people and delaying making decisions themselves until the LLM agent forces them to? Which is a fine approach but I don’t think the analogy with a compiler is necessary.
People seem to have a hard enough time understanding branch prediction and thread barriers.