Why the Best Agents Need the Discipline of a `const`

Nan Wang

Hatched by Nan Wang

Aug 04, 2026

10 min read

86%

0

The hidden problem with making an AI agent more capable

What if the real challenge in building a useful AI agent is not giving it more power, but giving it better constraints?

That sounds backwards at first. We usually imagine intelligence as something that expands with more tools, more memory, more freedom, and more autonomy. Yet the moment an agent can write code, run code, call tools, store state, and stitch together sessions, a new problem appears: capability becomes volatility. The system can do almost anything, but almost anything is exactly what makes it hard to trust.

This is where a deceptively simple programming idea becomes a design principle for AI agents. In TypeScript, const does not make a value magically immutable in every sense, but it does prevent accidental reassignment. It turns a variable from something fluid into something dependable. That tiny restriction is not a limitation on thought. It is a guardrail for reasoning.

The same logic applies to agents. A strong agent is not one that can endlessly reinvent itself mid-task. A strong agent is one that can hold certain commitments still while it explores, delegates, plans, and adapts around them.


Why unconstrained intelligence becomes hard to use

There is a temptation to think that an agent becomes better simply by adding features: persistent state, multiple model providers, tools, extensions, session trees, to-do lists, skills, and terminal interfaces. Each addition sounds obviously valuable, and each one is, in isolation. An agent that can remember context across sessions is more useful than one that cannot. An agent that can call a tool is more useful than one that must speak everything aloud. An agent that can persist state is more useful than one that starts from zero every time.

But there is a deeper pattern here: every capability increases the agent’s surface area for inconsistency.

Imagine asking a human assistant to help with a project, then giving them a blank notebook, a whiteboard, a sticky note system, three different calendars, and permission to rewrite their own memory whenever they want. That assistant might become more powerful in theory, but in practice you would quickly ask: which notes are authoritative, which plans are current, and what exactly is still true?

That is the central tension in modern agent design. The more an agent can do, the more important it becomes to define what it must not casually change. Without that discipline, persistence becomes clutter, tools become noise, and flexibility becomes a form of drift.

A useful agent is not just an improviser. It is a system that knows how to separate the stable core from the exploratory periphery.

Capability without constraint produces motion. Capability with constraint produces progress.

This is why the analogy to const is so useful. const does not eliminate change from a program. It localizes change. It says: this identifier should remain fixed, so the surrounding logic can safely evolve. In agent systems, the same principle can make the difference between a clever demo and a dependable collaborator.


The architecture of trust: what should an agent be allowed to change?

A productive way to think about agent design is to divide the system into three layers: identity, intent, and execution.

Identity is what the agent believes about itself and its environment. Examples include the current user, the active project, the session context, and long lived preferences. If identity shifts too easily, the agent becomes disoriented. A tool call that accidentally overwrites this layer is the equivalent of redeclaring a variable in the same scope. The system has not become smarter, only less coherent.

Intent is what the agent is trying to do. This includes goals, subgoals, open questions, and to-do items. This layer should be persistent enough to survive interruptions, but flexible enough to adapt when new information arrives. A to-do list is powerful precisely because it preserves intention without forcing immediate execution. It externalizes commitment.

Execution is the fluid layer where the agent actually writes code, calls tools, tests hypotheses, and explores possible responses. This is where volatility is welcome. In fact, an agent that cannot revise its execution strategy is brittle. The problem is not change itself, but change without boundaries.

This is where persistent sessions, tool access, and stateful extensions become especially interesting. They are not just features. They are mechanisms for distributing mutability across different scopes. A session tree can preserve branches of work without collapsing them into one overwritten history. A tool can be made available to the model without giving it permission to redefine the whole system. An extension can store state between sessions, but only if that state is treated as an intentionally managed dependency rather than a free-for-all memory dump.

A good agent architecture therefore asks a question that resembles the logic of const:

What should remain stable so the system can safely vary everywhere else?

That question is more important than asking for more autonomy. Autonomy without stable commitments often creates a wandering system that feels active but not accountable.


Sessions as trees, not puddles

One of the most revealing ideas in this space is to think of sessions as trees rather than linear logs or isolated buckets. A tree allows branching histories, alternative experiments, and distinct lines of reasoning to coexist without erasing one another. That matters because real thinking is not linear. We change direction, explore dead ends, test variants, and return to earlier assumptions with more information.

A tree structure matches the actual shape of thought better than a single mutable state object does.

Consider writing a complex piece of software. You might begin with a broad architecture, then branch into a prototype, then discover a better way to represent state, then fork again to test a new tool integration. If each new step overwrote the previous one, you would lose the very evidence that made the later insight possible. A tree keeps those branches legible. It makes the system more transparent to itself.

This is a profound design move because it reduces the pressure to keep everything in one place. Instead of one giant mutable memory, you get a structured history of commitments. Instead of asking the agent to remember every path as if nothing were ever discarded, you let it retain the paths that matter.

That is another const lesson in disguise. When a value cannot be reassigned, you are forced to create a new binding when the situation changes. That sounds like extra work, but it is actually a clarity engine. New bindings preserve the old state and make the transition explicit. In an agent, each branch of a session tree functions like a new binding: a fresh context with inherited ancestry, not a silent overwrite.

This matters especially when an agent has access to many tools and model providers. More providers mean more possible behaviors, more output styles, and more potential inconsistencies. A tree structure gives those differences somewhere to live without collapsing the whole session into ambiguity.


Extensions, tools, and the art of bounded delegation

There is another deep connection between language-level immutability and agent design: both are about delegation.

In code, a const declaration delegates less to the future. It says the name will not point to something else later. That limitation lets the rest of the code rely on a stable reference. Similarly, an agent extension system delegates certain powers to external modules, but only within a defined contract. A tool can be exposed to the model. State can be persisted. New behaviors can be added. But all of this should happen through a narrow interface that makes the delegated capability legible.

This is especially important for features like a to-do list. Giving an agent a to-do list is not impressive because it can store text. It is impressive because it gives the agent a place to put unresolved intent that is separate from immediate action. The list acts like a controlled mutation zone. The agent can revise plans there without contaminating the entire session state.

Think of it this way. A to-do list is to an agent what a const binding is to a program. It is a commitment device. It tells the system, and the user, what is considered stable enough to matter.

The same applies to skill modules or terminal extensions. These are not just convenience layers. They are ways of packaging behavior so that capability does not leak everywhere at once. A well designed skill is a bounded promise: if this action is needed, here is the interface, here is the state it can touch, and here is what it cannot silently rewrite.

The most successful agents may be the ones that are not maximally general, but maximally well scoped. They know how to say, in effect: I can do this, and I will do it here, with these limits.

That is the difference between a capable assistant and a manageable one.


A practical mental model: the const agent

If you are designing or evaluating an agent, a useful framework is to ask where you want const semantics and where you want let semantics.

Use const semantics for:

  • the user’s identity and permissions
  • the active objective for the current branch
  • durable preferences that should not change casually
  • tool contracts and expected outputs
  • provenance of decisions, so the system can explain why something happened

Use let semantics for:

  • intermediate hypotheses
  • draft outputs
  • execution strategies
  • transient tool results
  • branching experiments that may be discarded

This distinction is powerful because it shifts the question from “Can the agent change?” to “What kind of change is appropriate here?” That is a much more mature design principle.

A concrete example helps. Suppose an agent is helping debug a failing deployment.

The stable core might be: the repository, the production environment, the goal of restoring service, and the user’s preference to minimize risky changes. Those should behave like const. If the agent keeps reinterpreting the goal, or silently switching environments, trust evaporates.

The mutable layer might be: candidate hypotheses about the bug, alternative patches, rollback plans, and temporary commands executed in the terminal. Those should behave like let. They are supposed to evolve as the agent gathers evidence.

If the agent confuses these layers, the result is chaos. But if it keeps them distinct, it becomes both agile and dependable.

The best agent design does not minimize change. It classifies change.

That is a much richer idea than simple persistence. Persistence is not enough if the wrong things persist. Flexibility is not enough if nothing stays fixed long enough to be trusted. The art is in assigning each kind of information the right mutability.


Key Takeaways

  1. Treat constraints as a feature, not a weakness. Stable commitments make agents easier to trust, debug, and extend.

  2. Separate the stable core from the exploratory layer. Identity, intent, and execution should not all mutate at the same rate.

  3. Prefer structured memory over flat memory. Session trees preserve alternatives and reduce accidental overwrites.

  4. Use tools and extensions as bounded delegation, not total permission. Every tool should have a clear contract about what it can touch.

  5. Ask where const belongs in your agent. Wherever accidental reassignment would create confusion, make that part of the system harder to change.


The real lesson: intelligence needs syntax, not just power

The deepest connection here is not between a programming keyword and an AI feature set. It is between two truths about complex systems.

First, power is easy to admire and hard to control. Second, control is not the enemy of intelligence. It is what lets intelligence survive contact with reality.

An agent that can run code, call tools, persist state, and branch sessions is not automatically intelligent in a meaningful sense. It is merely more expressive. Expressiveness becomes usefulness only when the system has a grammar for what may remain fixed and what may safely vary. That grammar is the structural equivalent of const and let, of stable bindings and mutable bindings, of commitments and experiments.

So the next time you think about making an agent more capable, ask a better question first: what should this system refuse to forget, and what should it be free to revise?

That question reframes agent design entirely. The goal is not to build a system that can change everything. The goal is to build one that knows exactly what must stay still so that meaningful change can happen around it.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣