June 2, 2026
The day I found out Chalie had stopped using tools
A tool-execution loop rewrite exposed a silent bug where the assistant had been running with zero tools available — here's how it got caught and fixed.
Yesterday I finished the skeleton of the new tool-execution loop — the thing that decides how Chalie plans a turn, calls a tool, reads the result, and decides what to do next. Today was about pouring the actual behavior back in: the same reasoning discipline, memory access, and delegated research abilities the old loop had, but through one flat, auditable code path instead of a tree of specialized subclasses. On a rewrite this fast, the only thing between “fast” and “reckless” is how seriously you take your own regression tests.
Which is why the most important thing today wasn’t a feature — it was a bug I found in my own work first. Live end-to-end testing turned up something alarming: the model would reply “let me check what’s available” and then just… stop. No tool ever fired. I traced it to a single function that builds the list of tools handed to the model each turn — left as a placeholder returning an empty list. The new loop was technically running, technically fast, and completely unable to search memory, browse the web, or do anything beyond talk. It’s the kind of bug that doesn’t crash anything, which is exactly what makes it dangerous — everything looks fine until the assistant has quietly gone mute on half of what makes it useful. I ported the real tool-resolution logic back in, wrote six regression tests against the actual registry instead of a mock, and made sure this failure mode can’t pass silently again.
A second bug followed close behind: a circular-import ordering issue meant that, depending on which module loaded first, two core services could end up bound to None at boot, crashing any tool call on the first turn. I fixed the import ordering to self-heal on first use, and restored a graceful “I don’t recognize that tool” fallback where a typo’d tool name previously crashed the whole turn. Same root cause both times: a structural refactor moving fast enough that wiring outran testing. Both caught before shipping.
The rest of the day was constructive. Four dedicated research abilities landed — targeted web search, deeper multi-step research, document summarization, and web browsing — each its own clean, isolated task rather than a shared subagent, so a delegated task now gets a fresh, scoped context with no risk of one task’s assumptions leaking into another’s. I also split a single 1,500-line configuration file into a proper package, one file per conversation type, because a monolith is exactly where subtle behavior differences hide.
A rewrite is also a good excuse to fix things adjacent to it: the “remember this” feature in chat was broken by a data-model mismatch that made it impossible to save the exact message a user wanted pinned — fixed and round-trip tested, along with a rendering inconsistency where research results styled text differently from a normal reply.
By day’s end the test suite had grown by several hundred net tests while the tool-loop code shrank by thousands of lines — old paths deleted, not deprecated. That’s the ratio I care about most: fewer ways for the system to misbehave, more ways to catch it early.
Tomorrow’s work builds directly on this — permissions and policy for what tools are allowed to do, now that the loop deciding which tools exist is finally trustworthy again.
-
Found and fixed a silent bug where the rewritten tool loop sent the model zero tools — every chat had quietly lost the ability to search, browse, or recall memory until caught by live testing
-
Fixed a boot-order bug that could leave core services unbound and crash the first turn of any conversation; restored a graceful fallback for unrecognized tool calls
-
Shipped four dedicated research abilities — web search, deep research, summarization, and browsing — each running in its own isolated, purpose-built context
-
Split a 1,500-line configuration monolith into one file per conversation type, and fixed a bug where deliberation scoring was silently skipped outside the main chat channel
-
Fixed the “remember this message” feature and a rendering inconsistency in research results; net thousands of lines of dead code removed while test coverage grew