Building Agents? Stop Treating messages[] Like a Database
Stop using messages as your agent's memory. Learn how structured state makes AI agents more reliable, efficient, and production-ready.

Millions of developers now use agent-driven delivery tools like Claude Code, Cursor, GitHub Copilot, and OpenAI's Codex. In a short span, these tools have moved from suggesting a line of code in the editor to acting inside the pipeline, running commands, calling tools, opening pull requests, and touching infrastructure. They have become significantly more capable and accordingly, more powerful, but all that new capability and power also changes the amount of risk they bring.
When our teams speak with technology leaders, few have fully explored the potential, and fewer still have reckoned with the trade-off that rides along with it. The two of us come at this from opposite ends of it: one of us supports the teams that build the agentic systems that do the work, the other owns the standards, compliance, and controls those systems have to live inside. We keep landing in the same place.
The instinct is usually to look for a fix: lock this down, turn that off, and we're safe to scale. We understand it, but it sets the wrong expectation. You can't fix your way out of these risks, because the thing creating them is the same thing creating the value. An agent is useful precisely because it can act, and anything that can act can act wrongly.
So this isn't a checklist with a clean end state, it's a balance. Every guardrail you add spends a little of the agent's agency to buy safety. Every bit of autonomy you grant spends a little safety to buy speed. The work is deciding, on purpose, where on that line you want to sit, and the answer is different for a code-formatting agent than for one with deploy access.
The trade-off isn't diffuse, though. It concentrates in six places. Understand the failure mode behind each one and the mitigation that moves the balance, and you can grant agency where it's cheap and withhold it where the blast radius is large, instead of treating every agent as equally trusted or equally caged. Here are the six, with what goes wrong, what mitigates it, and what that mitigation costs you.
It helps to picture a single dial behind all six risks. Turn it toward agency and the agent does more on its own, faster, with less waiting on a human. Turn it toward safety and you add isolation, scope limits, and checkpoints that slow it down and narrow what it can reach. There is no setting that gives you both ends at once. What you can do is set the dial separately for each risk and each agent, so the autonomy you grant matches the damage it could cause. The sections below are six versions of that same decision.

An agent holding credentials can do anything those credentials allow, and a prompt-injected or compromised agent will. This is bigger than a leaked secret. Even when nothing ever leaks, the credential's authority is in use the entire time the agent runs, on the agent's judgment rather than yours.
The mitigation is to keep credentials out of the agent's reach. Run it in an environment with no secrets sitting in it, such as an isolated VM or container sandbox, and inject what it needs at runtime through a TLS-terminating proxy so it uses a secret without holding it. Keep every token narrowly scoped, short-lived, and rotated, enforced in the tooling rather than a policy document. In practice this is hard to do perfectly, so tier it the way you'd tier a person: the more an agent can be influenced by outside input or the closer it sits to production, the more you lock its credentials down. Most agent work today happens in secondary environments, which is what keeps this cost manageable.
The agency you give up: the agent can't reach into systems you haven't explicitly granted at runtime, so a few end-to-end flows will need a human to authorize a step. That pause is typically worth it.
You can usually control where an agent's traffic goes. You rarely control what's inside it. Untrusted content coming in is the prompt-injection channel: a poisoned file, issue, or web page that rewrites what the agent thinks it was asked to do. Sensitive data going out is the exfiltration channel. By default, neither direction is inspected.
Mitigate both directions. Whitelist outbound domains and deny the rest, run data-loss prevention on outbound traffic so secrets and source don't leave quietly, and scan for prompt injection at the LLM gateway on the way in.
The agency you give up: the agent loses free run of the open internet, so a task that needs a new source needs that source approved first, and the inspection adds some latency and cost. An allowlist shrinks the attack surface rather than closing it, since an approved domain can itself be compromised. That friction is the feature.
Anything an agent can do is something it can do wrong. That includes direct tools, like a server speaking the Model Context Protocol (MCP, a common way for agents to call tools and systems) or an API, and indirect ones, like a code push that triggers a CI job, a webhook, or a deploy. The indirect surface is the one teams forget: an agent doesn't need deploy rights if it can edit the workflow file that deploys.
Set an explicit policy for direct tools, covering which are allowed, why, and what they may touch. Prefer vendor-provided MCP servers, or ones you write yourself using public source as a template, over untrusted third-party servers; these are usually simple enough that there's no need to take on outside trust. Then reason through the indirect actions, especially an agent changing a pipeline definition that later runs with more privilege than the agent has, and put automated static analysis in the loop to catch those before they execute. Much of this maps onto pipeline security, a well-defined practice at the enterprise level.
The agency you give up: fewer tools wired in means more tasks the agent can't finish unattended, so you grant tools as trust is earned rather than all at once.
An agent running directly on a host machine can read, write, and execute anything the user can. The damage isn't always immediate, either. A planted git hook or a postinstall script can sit dormant and run later, the next time a person touches the repo.
Isolate the agent from the host with a VM, a container sandbox like Docker Sandboxes, or a tool like Coder, and treat the isolation boundary as a checkpoint: review anything that crosses back onto the host before it runs, including .git/hooks, package.json scripts, and Makefiles.
The agency you give up: the agent no longer runs free on the host, so sandboxing adds some setup and overhead and a human has to inspect anything crossing back before it runs. The speed you trade away is small next to a host you no longer have to trust blindly.
When many agents produce large volumes of code, the pressure moves downstream into review. At enough volume, reviewers fatigue, and "not really reviewing" gradually becomes the norm, which is the actual risk, because that's the last gate before production. An agent reviewing its own output is not an independent check. The volume isn't hypothetical: CodeRabbit's analysis of 470 pull requests found AI-co-authored changes carried about 1.7 times the issues of human-only ones.
Be specific about what review means, because at volume a vague gate becomes no gate. Deterministic tooling is the floor—types, linters, tests—catching whole classes of error before a human looks. Layer in system-specific skills that steer agents toward idiomatic patterns, and project-context reviewers that carry enough context to review adversarially rather than rubber-stamp. Never let the agent that wrote a change approve it, and keep a human at the gate that matters most.
The agency you give up: agents don't merge straight to production, so throughput stays bounded by review capacity. That bound is the point, because the gate is what makes the volume safe.
Once your code and prompts leave your environment, the provider on the other end may retain them, or use them to train its models. That puts proprietary logic and customer data outside your control, and often outside your jurisdiction.
Configure model and inference providers for zero data retention and no training on your inputs, and enforce it through process so that only approved enterprise tools and models are used rather than individuals choosing accounts under deadline. Where residency matters, prefer inference hosted in your own region.
The trade: you may pass on the newest consumer tool or the cheapest endpoint in favor of an approved one. A small price for keeping control of your data.
Four things govern where you set the dial: isolation, i.e. how contained the agent is; autonomy and scope, i.e. the permissions it holds and the human checkpoints in its path; governance, i.e. the change gates, approvals, and audit trail around it; and observability, i.e. how much of the agent's behaviour you can actually see. In traditional systems we monitor the application; with an agent we also monitor its decisions, its tool calls, its permission escalations, and its drift over time. Visibility usually comes before autonomy— most teams need to see what an agent does at one setting before they'll trust it at a higher one.
Before you grant a level of autonomy, size the blast radius by asking the plain question: if this agent were wrong, or hijacked, what is the worst it could do, and can we live with that? This maps onto the familiar risk equation of likelihood and impact, with one deliberate difference: once you're assuming the agent is hijacked or wrong, you've already set likelihood aside and let impact drive the dial. "It probably won't happen" is not a control when the failure is someone making it happen. A formatting agent earns a long leash. An agent with production access gets a short one and a human at the gate.
One control has no technical substitute: accountability. None of the usual consequences attach to an agent—its reputation isn't on the line, it can't be fired (at least not in a way that it can care about) or face legal jeopardy—so accountability can't be delegated to it. When an agent acts, a named human still owns the outcome, the way a project assigns an owner before work starts. The real risk is that this delegation happens implicitly: a person ends up answerable for decisions an agent made without ever consciously deciding to take that on. The industry doesn't yet have a settled model for this, especially as agents shift from carrying out decisions to participating in them. Tooling decides what an agent can do; accountability decides who answers for what it did.
None of these six closes to zero, and it's worth saying so out loud. Prompt-injection defenses are imperfect. Review at volume is probabilistic. A patient supply-chain attack can still hide inside an indirect action. The goal isn't a clean bill of health. It's residual risk you've seen, sized, and accepted on purpose, with enough instrumentation that you'd actually notice it turning real, not discover it after the fact. Most of these six will fail by being detected rather than prevented, which is exactly why the instrumentation is not optional.
Take one workflow and walk it through these six. For each, set the agency level deliberately and write down the blast radius you're accepting. You'll grant more leash in some places than you expected and less in others, which is the sign you're making the call rather than letting it make itself.
Done once, that walkthrough becomes a repeatable practice you can standardize across projects and share with clients. That's the work we do with teams getting serious about agents: not making the risk disappear, but turning the balance between agency and safety into a decision made with intent.
Stop using messages as your agent's memory. Learn how structured state makes AI agents more reliable, efficient, and production-ready.
Traditional approaches to change management weren’t working before. AI just makes the gaps impossible to ignore.
How smart companies are evolving with agent-powered delivery models, and what it takes to lead in the new era of intelligent services.