Anton, chapter 2: The first weekend
I woke up Saturday wanting to replace the parent agent that previously orchestrated routing between subgraphs.
The classify-and-dispatch graph from the previous day worked, but it asked the LLM to make routing decisions inside a state machine that was already trying to do the same thing.
Two layers fighting over one job.
The parent became a single agent with the domain subgraphs exposed as tools. The LLM could decide which tool to use from the request itself, while the framework handled the underlying execution.
The system immediately felt lighter.
The model was doing what it was good at: interpreting intent. The framework was doing what it was good at: managing state and execution.
Making Anton usable
The next changes were small, but they made the difference between a functioning system and something the family could actually use.
Anton gained a typing indicator and an acknowledgement message, so people knew he had heard them while the model was still thinking.
He began answering in the language of the current message rather than the language of the conversation history. French and English are freely mixed in our house, often within the same thread.
Schedules became natural language. You could simply tell Anton, "Remind me every morning," rather than learn a special command format.
He gained support for group conversations, daily summaries, and browsing previous exchanges.
I also added an explicit rule: Anton should never invent an answer merely to appear competent. My first attempt at grounding Anton's responses and mitigate hallucinations.
Reliability is not only about whether a system works. It is also about whether it admits when it does not know. Easier said than done, but we need to start somewhere so I added instructions to the prompt.
Asking for help
The first browser-driven workflow was Doctolib.
Logging in required two-factor authentication, which meant Anton had to pause midway through a task, ask the user for the SMS code, and then continue from where he had stopped.
The mechanism was simple: an interactive input queue.
But it solved a much broader problem. Many useful tasks cannot be completed autonomously from beginning to end. They occasionally require a password, a confirmation, a choice, or some other piece of human input.
Anton did not need to fail or hand the entire task back. He could ask for help and continue.
That immediately felt important.
Seeing inside the system
By Saturday evening, the main problem was no longer capability. It was visibility.
When Anton failed, I needed to understand why.
I added a pipeline that turned error traces into draft GitHub issues, so failures would leave behind something actionable rather than disappear into a log.
I added a simple /logs endpoint backed by an in-memory ring buffer. Reaching into Docker every time I wanted to inspect the system was a small inconvenience, but small inconveniences accumulate quickly when debugging.
Deployments were also moved behind a trigger file watched by systemd. Anton no longer had to run the deployment process synchronously himself. He could request an update, and a separate process would perform it and report back.
Decoupled, boring, reliable.
The kind of plumbing that disappears once it works.
The LCARS dashboard
On Sunday morning, I built Anton a dashboard.
Naturally, it was styled after LCARS, the computer interface from Star Trek.
It showed the health of each service, recent logs, conversations, and individual agent runs. From any conversation, I could drill into the execution trace and inspect what the model had done at each step.
This changed the pace of development completely.
Before the trace viewer, a wrong answer was simply wrong. After it, I could see whether Anton had misunderstood the request, chosen the wrong tool, passed bad context, or stopped too early.
Without that visibility, the rest of the weekend would not have happened.
Expanding what Anton knows
Once I could see what the system was doing, I began broadening its knowledge.
Anton gained the ability to search his own source code. He could research the web, browse documents, and store what he learned.
Research became its own domain rather than a capability buried inside every other agent.
That separation mattered. Research has its own concerns: cost, citations, source quality, fact-checking, and limits on how far the system should explore.
By Sunday afternoon, Anton could read the web, read his own code, and remember what he found.
From hoping to knowing
Then I wrote the quality suite.
It began with 28 tests covering the existing domains.
Until then, testing Anton meant sending him a WhatsApp message and deciding whether the answer looked reasonable. That works while a system is small, but it provides no protection against regressions.
The test suite changed the development loop from:
"Does this appear to work?"
to:
"Did everything that worked yesterday continue to work today?"
The gap between having no test suite and having one is the gap between hoping and knowing.
I should have built it on the first day.
The calendar saga
The tests immediately found problems.
The worst was the calendar agent.
It repeatedly failed on simple multi-step requests such as deleting an event with a particular title.
There were two separate causes.
First, I was passing the parent agent's full conversation history into the calendar agent. That context contained unrelated discussions and instructions, which contaminated a task that should have been narrow and precise.
The rule became simple: domain agents should receive only the context they need.
Second, the model could not reliably chain a search followed by a deletion. It would find the event, return the result, and stop before deleting it.
I had given the model two low-level tools and expected it to assemble them into a reliable operation.
The solution was to create a composite skill: findAndDeleteEvent.
This became another rule: when an operation must be reliable, do not depend on the model to discover the correct sequence of tool calls each time. Encode the sequence as a capability.
These were not principles I had arrived at in advance.
They were lessons learned by getting burned.
A wider household
By the end of the weekend, Anton's domains had expanded further.
He could manage a wine collection, process school messages, and understand images or audio posted in group conversations when someone explicitly asked him to.
For media, I used an "ingest cheap, process lazy" approach: store the original file immediately, but only invoke transcription or vision when it is actually needed.
There was no reason to spend compute interpreting every photo and voice message passing through a family group.
Media downloads became more capable, with release preferences and the ability to stop and resume transfers.
Torrent searches were routed through Tor, meaning all requests were anonymized and routed through the Tor network to reduce traceability and isolate the system from direct exposure to torrent indexers and their associated legal and network risks, a decision made less for new functionality and more as a precautionary architectural safeguard.
By Monday morning, Anton had seven domains, 73 quality tests, a dashboard for inspecting traces, automatic issue creation, accessible logs, and a development loop I could trust.
I could change almost anything and quickly see what broke.
The lesson from the weekend was simple:
Write the tests before the bugs do.
Not because discipline is inherently virtuous, but because I had now experienced the alternative.