The Best Coding Agents Think Like Samplers
Hatched by Nan Wang
Aug 16, 2026
12 min read
0 views
91%
A coding agent can appear to work like a very fast employee: you describe a feature, it edits several files, runs tests, and returns with an answer. But that picture misses the more important transformation. The deepest change is not that software can now be written by asking for it. It is that programming is becoming an iterative process of conditioning.
You do not need to hold the entire codebase in your head before making progress. You can fix some facts, revise one part of the system, observe the consequences, and then use those consequences to revise another part. The work advances through a sequence of partial views, each one narrowing what the next move can plausibly be.
This sounds like a description of a modern AI workflow. It is also the central logic behind one of the most useful methods in computational statistics: Gibbs sampling.
The connection is more than a clever analogy. It reveals why coding agents feel unusually effective in some environments, why they fail spectacularly in others, and how to design a workflow that turns local revisions into global understanding.
The impossible demand for a complete mental model
Traditional programming often assumes a sequential act of comprehension. First understand the architecture. Then identify the right abstraction. Then implement the change. Finally verify that nothing important broke.
That sequence is sensible, but it contains an unrealistic premise: that a person can construct an accurate joint model of a large software system before acting on it. In a mature codebase, the relevant facts are distributed across source files, tests, configuration, database schemas, command line behavior, deployment scripts, documentation, and historical conventions. The system is too large to fit cleanly into working memory.
As a result, programmers often alternate between two bad strategies. They either make a local change without understanding the surrounding constraints, or they postpone action while attempting to understand everything first. The first produces regressions. The second produces analysis paralysis.
An AI coding agent changes the balance because it can repeatedly inspect the environment, make a targeted modification, execute a test or command, read the result, and update its next action. Its advantage is not simply speed of typing. It is the ability to perform many cheap cycles of context gathering, intervention, and correction.
That cycle resembles Gibbs sampling.
Suppose we want to understand a collection of related variables whose full joint distribution is difficult to sample directly. Gibbs sampling takes a more manageable route. It updates one variable while holding the others fixed, then updates another variable using the newly updated information. After enough iterations, the sequence of states can approximate the joint distribution.
The method works because a difficult global problem can be navigated through a series of tractable conditional problems.
Software engineering has the same structure. The global question might be: “What change will make this feature correct across the entire application?” That question is too broad to answer in one step. More useful conditional questions are:
- Given the current API, what should this module return?
- Given the existing tests, what behavior is considered stable?
- Given the database schema, which validation belongs at the boundary?
- Given the observed error, which assumption is probably false?
- Given the current implementation, what is the smallest experiment that could distinguish two explanations?
The codebase is not solved all at once. It is progressively sampled through conditional questions.
The practical unit of intelligent software work is not the answer. It is the next well chosen conditional question.
Why local correctness can create global understanding
At first glance, holding variables fixed seems like a limitation. If the whole system is interconnected, why freeze part of it? Why not reason about everything simultaneously?
Because constraints are valuable. A fixed variable is not merely something excluded from thought. It is information that reduces the space of possible actions. When a coding agent examines a failing test while keeping the public interface unchanged, the interface acts as a boundary condition. When it edits an implementation while preserving the test suite, the tests define the region of acceptable behavior. When it checks a command in a real shell, the environment becomes an empirical constraint on what is actually true.
The workflow becomes productive when each local move is made inside a sufficiently informative context.
Imagine a small online store with a checkout function. A payment request is occasionally duplicated. A naive approach might ask an agent to “fix duplicate charges,” inviting a large and vague rewrite. A conditional approach breaks the problem into linked updates:
- Keep the payment provider contract fixed and inspect whether retries can repeat the same request.
- Keep the retry policy fixed and inspect whether the request has a stable idempotency key.
- Keep the request format fixed and inspect whether the database records successful attempts before or after the external call.
- Keep the storage behavior fixed and write a test that simulates a timeout after the provider has charged the card.
- Revisit the retry policy using what the test reveals.
No single step contains the whole answer. Yet each step changes the conditional landscape for the next one. A previously invisible relationship becomes visible because the system has been probed from a better position.
This is also why an agent that can use tools is fundamentally different from one that only generates text. A text model can propose a plausible patch. An environment connected to files, tests, logs, and commands can condition its proposals on reality. Each tool result becomes a new observation, and each observation can alter the next state of the investigation.
The result is not autonomous magic. It is a controlled chain of revisions.
The hidden danger: chains can converge to the wrong place
The statistical analogy also exposes a serious danger. A Markov chain can converge, but convergence does not guarantee that the result is useful if the assumptions, conditional distributions, or starting state are wrong. In software work, an agent can repeatedly revise a codebase and become more internally consistent while drifting further from the real requirement.
Consider a task described as “make the report load faster.” The agent profiles one endpoint, adds caching, sees an improvement in a local test, and then adjusts serialization, database queries, and UI polling around that change. After several iterations, the system may be faster in the measured scenario but wrong under permission changes, stale data, or concurrent updates.
The chain has settled into a coherent local basin. It has not necessarily found the intended product behavior.
This suggests three conditions for reliable agentic work.
The conditionals must be informative
A request such as “clean up this code” provides a weak conditional distribution. There are too many plausible actions, and the agent has little basis for choosing among them. A request such as “preserve the public function signature, add coverage for expired sessions, and verify the behavior with the existing test command” provides much stronger constraints.
Good instructions do not merely state an outcome. They specify the evidence and boundaries that should govern the next update.
The state must be observable
A chain can only learn from the signals it receives. If tests are sparse, logs are misleading, or the agent cannot execute the relevant workflow, its revisions are guided by imagined feedback. The code may look increasingly polished while the actual system remains unknown.
The highest leverage investment in an AI assisted workflow is therefore often not a better prompt. It is better observability: focused tests, meaningful error messages, reproducible commands, explicit invariants, and small fixtures that expose important behavior.
The chain must be able to move between plausible explanations
An agent can become attached to its first hypothesis. Once it has edited several files around the idea that a bug is caused by caching, later evidence may be interpreted through that frame. It keeps refining the same explanation rather than considering that the bug originates in authorization, serialization, or clock handling.
This is a software version of poor mixing. The process explores only one neighborhood of the possibility space.
To improve mixing, deliberately introduce hypothesis changes. Ask: “What evidence would show that this diagnosis is wrong?” Revert speculative changes. Compare two minimal implementations. Run a test that targets an alternative cause. A productive workflow is not one that avoids wrong hypotheses. It is one that makes them cheap to abandon.
The agent is not the programmer. It is a transition operator
Thinking in terms of Gibbs sampling changes how responsibility is assigned. The agent is not best understood as a junior developer waiting for a complete specification. Nor is it a magic oracle that produces the final design from a single request.
It is more useful to see the agent as a transition operator. Given the current state of the repository, the current instructions, and the latest evidence, it proposes a new state. The human determines which variables should be held fixed, which observations count as evidence, and when the resulting state is acceptable.
This reframes the human role from typing code to designing the chain.
A strong engineer supplies the structure that makes local updates globally meaningful. That includes:
- choosing the boundaries of the task;
- identifying invariants that must not change;
- deciding which test or observation should follow each modification;
- detecting when the process is stuck in a narrow explanation;
- and recognizing when a locally attractive change violates a broader purpose.
This is why vague delegation often disappoints. “Build the feature” leaves the agent with an enormous, poorly conditioned state space. The agent must infer architecture, priorities, hidden requirements, and acceptable tradeoffs simultaneously. It may produce something plausible, but plausibility is a weak form of convergence.
A better instruction creates a sequence of constrained transitions:
Inspect the existing authentication flow. Do not change the token format. First identify where expired sessions are detected. Then add a failing test for the intended response. Implement the smallest change that passes it. Run the focused tests, then the full suite. Report any assumption that remains unverified.
This kind of instruction does more than improve output quality. It makes the reasoning inspectable. Each step leaves evidence about what the system believes and why.
From coding sessions to knowledge accumulation
There is a deeper consequence. Iterative agentic work can turn a codebase into an accumulating record of conditional knowledge.
A single patch may solve a bug. A patch accompanied by a regression test records a relationship: given this input and this state, this behavior must hold. A clear error message records which boundary failed. A small command that reproduces the issue records how to revisit the state later. Over time, these artifacts make future transitions more accurate.
In statistical language, the system gains better access to its own conditional structure. In engineering language, it becomes easier to change safely because the important dependencies are made visible.
This explains why tests are not only safety nets. They are learning infrastructure. They give both humans and agents a way to ask localized questions of a complex system. A test suite with carefully chosen cases does not describe every possible state, but it provides landmarks that prevent the process from wandering without feedback.
The best tests are therefore not merely numerous. They are strategically placed. They pin down public contracts, failure modes, security boundaries, and irreversible side effects. They make the most consequential variables observable.
The same principle applies to documentation. A short note explaining why a cache must be invalidated after a particular write may be more valuable than a long description of what the code appears to do. It preserves a conditional dependency that would otherwise be rediscovered through failure.
A practical protocol for conditional software work
The following protocol can make AI assisted programming more reliable immediately.
1. Define the invariant
Before asking for a change, state what must remain true. This might be an API signature, a migration compatibility rule, a security property, or a user visible behavior. An invariant prevents local optimization from silently changing the problem.
2. Choose the smallest informative slice
Do not begin with the entire repository if a focused module, test, log, or command can discriminate among the leading explanations. Narrow context is useful when it is chosen to answer a specific question.
3. Make one meaningful update
Large batches of edits destroy information. If five changes happen before a test is run, a passing result tells you little and a failure tells you less. Small transitions preserve causal clarity.
4. Demand an observation
Run the test, inspect the output, reproduce the request, query the database, or compare the generated artifact. A proposed change without an observation is only a hypothesis.
5. Recondition the next move
After each result, update the question. Do not simply continue the original plan. If the error changed, that is information. If the test passed for an unexpected reason, that is information too.
6. Check for global drift
At intervals, zoom out. Does the implementation still serve the product requirement? Have temporary assumptions become permanent architecture? Has the agent optimized a proxy rather than the outcome?
Key Takeaways
- Treat programming as a sequence of conditional questions, not a demand for one complete answer.
- Hold important invariants fixed while changing one meaningful part of the system. Constraints make exploration more intelligent, not less creative.
- Invest in observability through focused tests, reproducible commands, useful logs, and explicit failure cases. Agents improve only when reality can correct them.
- Prevent poor mixing by testing alternative explanations, reverting speculative work, and asking what evidence would falsify the current diagnosis.
- Judge convergence against purpose, not just consistency. A codebase can become internally coherent while moving away from what users actually need.
The most important shift is conceptual. An AI coding agent does not eliminate the need for understanding. It changes the form understanding takes. Instead of trying to possess the whole system in advance, you can design a disciplined process that extracts understanding through repeated, evidence bearing updates.
That process has a human responsibility at its center. Someone must decide which facts are fixed, which observations matter, and whether the current state is closer to the real goal. The agent can traverse the landscape, but it does not define the destination.
The future of programming may belong less to those who can write the most code than to those who can design the most informative sequence of changes.
Once you see software work this way, the promise of coding agents becomes more precise. Their value is not that they replace thought with automation. Their value is that they make it economically possible to ask a complex system many small questions, rapidly and concretely, until the shape of the whole begins to emerge.
Sources
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 🐣