In his ElixirConf EU 2025 presentation [1], Chris McCord demonstrated Phoenix.new [2], an LLM-augmented VS Code in a browser that knows how to build Elixir/Phoenix apps.
McCord began by reviewing the current scripted and templated Phoenix code generator. He then showed how a tool-invoking LLM agent could be implemented in one screen of Elixir code. The bulk of his talk demonstrated generating apps with the Phoenix.new tool. It was interesting to see the tool generate development plan and begin coding to implement the plan.
I was fascinated to hear McCord explain and critique the LLM agent as it generated a Phoenix app.
"[It's] going to come up with a plan for our app and codify that into a Markdown file."
"Now it's going to take our high-level plan and make it into an expanded plan for us and itself."
"You can say, 'I changed the plan; execute the plan.'"
"We just recursed in the server and we did a req post. It's doing a req post right now and the tokens are coming back!"
"The agent just invoked a tool, which is 'I'm going to create a file.'"
"Hopefully it does a 'surgical modify tool,' which makes it not have to modify the whole file."
"A run-time error! Oh, no! Live coding is terrible. Oh, wait. It knows I need to add some missing functions here."
"You would be like, 'Oh, no, the page broke. What happened? I'm going to look at this error.' We just send that thing back to the chat completions endpoint and magic comes out and fixes the error."
"It didn't change a web file. We should fix that."
"This is an issue that humans hit; Steff and I need to fix that."
"It added the input at the bottom. That's not ideal."
"The agent decided to idle here. ... The way I implemented this is everything the agent responds with is a tool call and it has an idle tool and that's what it invokes when it is done."
Yeah. I was there and this demo was a jolt. More so was the phrasing we were witnessing the end of our punchcard era. I don’t know if it’s the history nerd in me or what, but that thought has been living in my head ever since. Looking forward to playing with Phoenix.new—and keeping an eye out for looms to smash. Kudos, Chris.
yes large parts of it were built with itself, including non elixir/phoenix things. The entire headless browser (node playwright script) for example was made inside phoenix.new and it iterated on itself. More to come soon!
I went down the "make your own Forth" rabbit hole about 45 years ago.
In January 1979, Byte Magazine's Language Forum contained the article, "IPS, An Unorthodox High Level Language."[1] The article described IPS, a language based on Forth, but with the word names translated to German. Thus, Forth's SWAP became VERT, short for vertauschen. The intriguing article concluded with a reference to Charles Moore's 1974 paper, "FORTH, a New Way to Program a Minicomputer,"[2] which was discussed on HN in 2022.[3]
I had recently assembled a Quest Electronics Super Elf computer[4] with an expanded memory size of 4 KB. The IPS article mentioned implementations under 6 KB for 8080, 6502, and RCA COSMAC microprocessors, so I thought Forth might fit. The Super Elf included an 1861 video display controller chip, with a resolution of 64 x 128 pixels (big pixels!). I designed a font of 3 x 5 pixel characters to provide 21 lines of 16 characters. Good luck distinguishing M, N, H, U, and W without some context. I bought a (possibly surplus) keyboard from Radio Shack and screwed it onto a wedge of wood to achieve a usable typing angle.
Moore's paper described about 75 Forth words. I wrote them on index cards and jotted down Forth definitions or RCA 1802 assembly code. I wrote an 1802 assembler in Fortran to ease the conversion into 1802 machine code. I still have the printouts and punch cards in storage.
Development proceeded slowly. During a break at work, I would punch my assembly code for a few Forth words, run the assembler, and bring home the printout. That night I would load previous work into the Super Elf from cassette tape, key in the new words (and changes) via the Super Elf's hex keypad, and save back to another cassette tape. Then I would test the new Forth words and note any changes needed on the printout. Lather, rinse, and repeat until, at last, it all worked.
The finished Forth system consumed a little more than 3 KB of the 4 KB of memory. User programs, data, and Forth stacks occupied the remaining memory. The R key stuck. The @ symbol was a 3 x 5 pixel blob (this is the very important Forth memory fetch operator). But it worked!
I demonstrated the system at the local personal computer club--spun off from the local ham radio club. Based on their enthusiasm, I advanced to developing tinyForth[5] for the TRS-80, a story for another day.
I started writing forth few months ago, wrote few interpreters, with jit or with types etc, and its just amazing, I think anyone should do it. TBH I don't think any other exercise has thought me as much about programming as this.
I also notice the "return" of Forth, as it is probably the easiest high level language to make for computers with addressable memory and fetch execute cycle. The parser is just few lines of assembly and of course you can write the parser in the inner interpreter's bytecode, you don't even need assembly :) So hobbyists can just "make it" and make their own tiny operating systems with it. Of course everyone makes their own dialect, but I think thats OK. Things like https://github.com/howerj/lfsr LFSR CPU/VM running Forth, or UXN or duskos/collapseos.
Now you can also use language models to help you onboard into the language, it do some practice programs and rewrite one program in many ways.
So if you are young or old and never tried to Forth, don't miss out, its super fun.
Howerj has a really easy subleq/muxleq interpreter. Eforth under Muxleq runs fast enough (perfectly usable) under an ATOM n270. Subleq too, but Muxleq it's must faster.
What kind of programs would one naturally reach for Forth as the optimal solution? It has always struck me as a very low level language but I rarely hear this caveat from its advocates.
I highly doubt it's useful these days on general purpose computers, where even the very smallest ones can easily implement C (or better) or even run a whole operating system like Zephyr or Yocto.
However if you're creating your own computer from scratch or have other artificial constraints (like it needs to fit into a boot sector[1]), and if you want to really understand precisely how your language works down to the lowest level detail while still having high-ish level constructs, then Forth is the ideal small language for that.
It made more sense in the 8 bit home computer era, where you could do a more high level coding with more performance than a BASIC interpreter, without having to mess with hexdumps for DATA segments, or Assembly opcodes.
1. Assembly coding within a REPL. Forth supports "load-and-store" without the additional bookkeeping steps of assembly. Once the program works, it can be incrementally rewritten into the assembly if needed, or used to bootstrap something else. Historically this is probably the single biggest usage, because the language works as a blunt instrument for that within the standard wordsets. Lots of programs on the early micros shipped with code that was developed with Forth, but with the Forth interpreter discarded at the last step; and where there is novel hardware and novel applications, Forth tends to come up as the bootstrap.
2. Minimal-dependencies coding. For the same reason that it's a good bootstrapping tool, Forth ends up being portable by assuming nothing. While different Forth systems are all subtly incompatible, the runtime model is small enough to wrangle into doing what you want. Stack machine VMs basically are "Forth with more sandbox and less human-readability".
3. "Big ideas" coding. The "human-readable stack machine" aspect means it's a useful substrate for language design - being programmable, you can shift the imperative interpreter model in the direction of new syntax and new general-purpose data structures, while still retaining a way to drop all the way down to assembly - the biggest downside is that this doesn't let you easily introduce existing library code, so bootstrapping from within Forth would take a long time and you would most likely get stuck on trivial string processing. But Forth as the second of a two-step process where you "compile to Forth" using something more batteries-included is actually pretty reasonable as an alternative to generating a binary or designing an original VM.
I have yet to use Forth for anything serious, but it's worth pointing at an example for how expressive you can be dealing with hardware. From https://www.forth.com/embedded/#Embedded_Programming_Example the top level control for a washing machine could be:
: WASHER ( -- ) WASH SPIN RINSE SPIN ;
I won't repeat all the rest, even though it's short, but let's look at a few other definitions that build up to that:
: RINSE ( -- ) FILL-TUB AGITATE DRAIN ;
: DRAIN ( -- ) PUMP ON 3 MINUTES ;
: ON ( mask -- ) PORT C@ OR PORT C! ;
4 CONSTANT PUMP
01 CONSTANT PORT
All very high level and fairly straightforward to understand word-by-word until you get to the bottom, that being the last 3 lines I pasted. (Though in a file this would be written the other way around with WASHER being the final line.) The PORT is a memory mapped hardware address, PORTB on a 68HC12 chip, and various other constants like PUMP are defined as bitmasks to get at individual bits on the port. The ON word takes the current value at the PORT address, ORs it with the stack-passed mask, and sets it back.
In C this might look like (again in reverse order):
That is, if you program the C in a similar procedural style that closely follows the physical function of the device. It's maybe more common to express similar C code in a state machine style, in which case it'd look a lot different.
Is the Forth version actually worth it? To me the C is "good enough", and more explicit or at least clearer as I'm familiar with C. Where Forth could win me over is in its ease of having a truly interactive environment to iteratively develop the software via a REPL, much like Lisp. (But then I'd rather just use Lisp.) My embedded systems hobby work for the last 10+ years has all been really simple, though, so interactivity isn't a big enough advantage to just using C. (When working with hardware, it's somewhat exciting to stick a pin in a breadboard and move it between power and ground to toggle a motor. It'd be even more exciting to do this interactively via REPL commands poking at memory.)
A lot of the power of Forth comes from its metaprogramming capabilities and having the compiler available at runtime, all wrapped in a tiny footprint. Similarly to Lisp, it empowers one to explore a problem domain without getting in the way. These concepts are alien to C which is downright hostile to exploratory programming.
If you really want to understand the genius of Forth and its creator, I suggest reading everything that Chuck Moore put down in writing starting with "Programming a problem-oriented language".
A lot of us today, being bogged down in the sort of tedium-inducing programming that pays the bills, tend to forget that programming languages are (or should be!) primarily about expressing ideas. Forth is still one of the best languages to do that in.
Yeah. Pretty much agree with everything here. I'd rather encourage starting with the book Thinking Forth, though. It's not written by Moore but has some commentary from him included in it.
I'd even suggest learning a little Forth to people even if it didn't have its interactive nature (which again I don't actually find useful in my own limited embedded work, there's really no "explore" phase as the problems are all straightforward -- contrary to software I write in CL or even Java). I had a friend in college who for a project made his own language and got it working on an embedded system (I think via compiling to C, but I don't recall exactly), but it was just a boring Algol-like somewhat inspired by Ruby. That pattern has shown up again and again around the world though. Forth is one of the handful of languages that shows what expressive options there are that aren't just transparently Algol-like.
It's used in a number of EFI implementations. Its good when you have no environment at all, hence bootloaders. Factor is a more general purpose forth-like language.
The New York Times reported [1] that at least three other tall ships have struck the Brooklyn Bridge.
In 1921, the steel mainmast on the six-masted schooner Edward J. Lawrence was bent as the vessel was being towed under the bridge at high tide. [2]
In 1935, the first three of four steel masts were bent as the Hamburg-American freighter Tirpitz passed northward under the bridge during an "abnormally high tide." [3]
In 1986, a radar was knocked out of commission when the South Korean freighter Hai Soo scraped the bridge while heading south. [4]
A similar book is Ryan North's "How to Invent Everything: A Survival Guide for the Stranded Time Traveler." It is framed as part of a user manual for a rental time machine that can travel as far back as 12,100,000 BCE and return to the present day. Should the time machine break during a visit to the past, the "Repair Guide" section of the manual helpfully explains: "There are no user serviceable parts inside ... ." The rest of the manual (about 400 pages) "contains all the science, engineering, mathematics, art, music, writing, culture, facts, and figures that are required for one human—without any specialized training—to build a civilization from the ground up."
I read that book cover to cover when it came out and it was pretty cool. It won’t get us back to advanced semiconductors because there is just too much to reinvent to get there but it would get us back to 1930s type lifestyle with modern niceties on top.
Brad Templeton's Robotaxi Timeline[1] (October 2024) shows a dozen milestones that Waymo has achieved over nearly 15 years from "Make a nice video" to "100,000 Rides per week." Waymo needs two more milestones to achieve "Production!" Waymo's competitors are behind on the timeline, but may move faster thanks to improved technology and a more welcoming social environment.