I think it's important to have a more first-principles intuition for what LLM-assisted tools are actually doing. Stripped back to the essentials, all of these tools are some variation on the same loop: construct a prompt, send it to a model, read the completion, and decide what to do next. The interesting part is not magic, but how much structure you wrap around that loop.
The project starts with a deliberately minimal script, complete.js, which is little more than a completion REPL. From there it steps up
to chat.js, where conversation state is introduced, then to simple tool-using agents like weather.js and assistant.js.
Each stage adds a small amount of machinery, but also makes the behaviour much easier to reason about.
The final version, programmer.js, is a more complete local programming agent. It has explicit prompt formatting, parsing for tool calls,
a control loop that executes those tools, and a workspace-scoped set of programming utilities for reading files, writing files, listing directories,
and running shell commands. The overall architecture is still intentionally simple enough that you can understand it end-to-end without much ceremony.
I think there is a real benefit in building systems like this from scratch, even if you later end up using more polished tooling. It forces you to see where the boundaries really are between the model, the harness, and the external environment, and makes a lot of current "agent" discussion feel much less mystical.
The code is designed to run against a local completion endpoint such as LM Studio with a Gemma 4 model. On my machine, gemma-4-E4B has been
capable enough for simple programming tasks while remaining practical to run locally.