Agent Patterns: Memory, Tools, Scheduling
The capabilities of an agent have stopped moving. The models are, of course, still improving, but the arrangement of a useful agent has settled. A couple of years ago every framework had its own idea of what an agent was for, and the answers were all different. Now, looking at the agents I’ve built, the ones colleagues have built, and the ones that ship as products, they’ve all converged on the same three things: memory, tool use, and scheduling.
The list isn’t very surprising once it’s written down. What I’ve found more interesting is that most of the difficulty is in how the three connect to each other, rather than in any one of them individually.
Tools the agent writes for itself
The biggest single improvement I’ve made to any agent is letting it write its own tools and execute them live.
The reasoning is fairly simple. When an agent performs a task by reasoning through it in the context window, you get a slightly different answer each time. Ask it to reconcile a CSV against an API five times and you’ll get five subtly different reconciliations. They won’t necessarily be wrong, but they won’t be the same either. That’s fine when you’re exploring a problem and much less fine when you’re producing a number someone else is going to act on.
If instead you ask the agent to write a script that does the reconciliation, run it, and check the output, the variability collapses into a single act of authorship. After that the code is just code. It does the same thing every time, and you can read it, test it and version it. The agent can also read it back in a later session and decide whether to reuse it or improve it.
This is the difference between an agent that does the work and an agent that builds something which does the work. The second one accumulates. It converts a probabilistic process into a deterministic one, and it does that once per problem rather than once per invocation. It also makes the output reviewable by a human who wasn’t in the room at the time, which matters more than I expected it to.
Memory at both ends
Memory is where most of the agents I’ve seen are weakest, and the weakness is rarely in the storage. It’s in when the memory gets called.
Memory needs to be the first tool called and the last tool called in a sequence of actions. It needs to be first because an agent that starts a task without reading what it already knows is starting from nothing every time, and will happily rediscover last Tuesday’s conclusion in a slightly different form. It needs to be last because an agent that finishes a task without writing down what it learned has thrown away the only durable output of the session. Read at the start for grounding, write at the end for accumulation, and everything else happens in between.
The grounding half matters more than people tend to assume. An agent with good memory doesn’t just recall facts, it recalls your facts: that this client uses a non-standard branch naming convention, that the staging database is the one with the odd hostname, that you already tried the obvious fix and it didn’t help. That’s the same context which makes a human colleague useful after six months and fairly useless in their first week.
The accumulation half is what makes the effort worthwhile. Memory only becomes useful as it grows. A store with ten entries is barely worth querying; one with a thousand well-formed entries changes the character of every session that follows. This is a little uncomfortable to build, because the cost is immediate and the payoff is deferred. You have to write the memory tooling a long time before it earns its keep.
Scheduling, reaction and trust
An agent you operate yourself is useful. An agent that acts without being prompted is the more valuable end state.
At the moment most of the value in an agent is gated behind my attention. It sits there, capable, until I open a terminal and give it something to do. What I actually want is an agent that reacts to external events, whether that’s a webhook, a failed build, a new ticket, or a threshold being crossed, and does the work before I’ve thought to ask for it. Reacting to events is what turns a tool into something that acts on your behalf.
Independent action requires a lot of trust, though, and trust can’t be granted up front. It gets earned in much the same way a new hire earns it, by doing small things correctly and visibly until the supervision starts to feel like a formality.
So the sensible path is a graduated one. Start with the agent proposing actions for you to approve. Then let it act on a narrow, well-defined class of events where the worst case is cheap to recover from. Widen that class as the track record builds up. There isn’t a way to make this fast, because the accumulated evidence is the whole point. An agent that has correctly triaged four hundred alerts has earned something that an agent on its first day can’t be given.
A final observation: agents are remarkably good at reflecting on their own behaviour, and in my experience almost nobody asks them to.
I’ve started building in what I think of as therapy loops. Periodically, either after a long session or on a schedule, the agent is pointed at its own history and asked some version of the following. Where did you misuse a tool? Which of these memories are wrong, stale, or duplicated? What did you record confidently that turned out to be false?
The results are good. Agents will identify that they’ve been reaching for a search tool where a direct lookup was available. They’ll spot that they’ve written the same fact three times in slightly different words. They’ll find a memory that was true back in March and isn’t true any more. These are all things I’d otherwise have to notice by hand, and in practice I wouldn’t notice them, because nobody wants to audit a memory store on a Friday afternoon.
This is the same effect as the periodic review sessions I described in an earlier post on building momentum. An LLM is quite good at finding its own mess when you explicitly ask it to look, and it never volunteers. The reflection has to be scheduled, which is a good use for the third corner of the triangle.
Between them, tools give an agent repeatability, memory gives it grounding, and scheduling gives it independence. I don’t expect a fourth item to appear on that list. The engineering effort is mostly in the joins: memory that isn’t read at the start of a task is a filing cabinet nobody opens, tools that aren’t remembered get rewritten from scratch every week, and scheduling without either of the other two is an expensive way to run a cron job.