$ Desired-State Development: Declare What Must Be True, Then Reconcile
Goals break down as they grow: they outgrow the box, turn into pointers to files, and get judged by what the working agent chose to show. Desired-state development declares what must be true instead, and lets a governing agent, increasingly a personal assistant, reconcile toward it until the evidence and the owner's verdict say it holds.

The goals kept getting better, and that was the problem.
I have been giving agents goals instead of steps for a while now. A few weeks ago I wrote that goal mode had changed what I delegate to Codex: a goal gives work a trajectory instead of a sequence of disconnected prompts. I still believe that.
But every time I made a goal more precise, it got harder to pursue.
First it outgrew the box. Codex accepts a goal objective of at most 4,000 characters, and a Claude Code /goal condition has the same ceiling. For a completion condition, that is a reasonable design choice. For a detailed description of a real piece of work, it is not much room.
So the goal moved into a file, and the file became the next problem. Codex’s documentation says that “the goal text becomes both the first prompt and the completion criteria for the task.” Its open-source terminal client shows what happens when the text is too long: it writes the objective to a file and replaces the goal with a single sentence, Read the Codex goal objective file at {path} before continuing. What was supposed to define completion is now an instruction to go read something.
Then someone has to decide that the goal is done. Codex asks you to “write a goal that lets ChatGPT verify its own progress.” Claude Code deliberately gives the decision to a separate model, “rather than the one doing the work,” which is the right instinct. But its documentation is candid about what that judge can see. It “doesn’t run commands or read files independently.” It judges what the working agent chose to surface.
None of these are bugs. They are sensible trade-offs. Together, though, they describe something I kept running into: the specification itself starts becoming the work. Did the agent read all of it? Did it decide that four out of six requirements was close enough? Is the work finished, or did the agent just reach a point where it felt finished?
Infrastructure engineering ran into a version of this problem a long time ago, and it got out by changing the question. Stop describing the steps. Declare what should be true, and let a controller keep reality close to it.
I’ve started calling the version of that I want for agents desired-state development. I don’t claim the idea. Configuration management has been converging machines toward declared states since the nineties, Kubernetes made reconciliation everyday vocabulary, and this summer Addy Osmani gave loop engineering its name: “replacing yourself as the person who prompts the agent. You design the system that does it instead.” What I want to add is the thing those loops converge on: a declared state, and a clear answer to who is allowed to say it has been reached.
There’s also a reason this feels practical now rather than theoretical. Agents are finally good enough to infer a messy gap between what is and what should be. The harnesses expose ways to dispatch work into them from outside. And a new kind of product is arriving that could hold the whole loop for weeks at a time: the persistent personal assistant.
A goal is still an instruction
One string, two jobs. A goal has to tell the agent what to do, and it has to define what finished looks like. For a small objective those are the same sentence. For real work, they pull apart.
In the feedback loop series I gave an example of a good prompt that reads like a specification:
Add JWT authentication with:
- /register and /login endpoints
- Password hashing with bcrypt
- Token expiration: 24 hours
- Middleware to protect routes
- Tests covering all endpoints and edge casesThat was a much better instruction than “add authentication.” It is still an instruction. It describes work, and it ends when the work ends.
A desired state describes something else: what must be true, and how we would know.
Desired state: authentication is production-ready
- Users can sign in with Google and with email and password
- Unauthenticated API requests receive 401
- Sessions survive a browser reload
- Refresh-token behavior has integration coverage
- No credentials are committed to the repository
- A new developer can run auth locally from the READMEThe difference sounds like wording. It isn’t. A goal finishes. A state holds or it doesn’t, and it can stop holding next week because a dependency changed. A goal is something an agent completes. A state is something a system keeps true.
It also changes what a file is for. When I moved my detailed goals into files, I was moving prose: context the agent might read carefully, skim, or reinterpret. A file of assertions, each with a way to check it, is a different kind of thing. It isn’t context. It’s a target. That difference matters later, because it is what turns a short pointer to a long file from a liability into a design.
We already know how to declare a destination
Infrastructure made this shift years ago. Instead of writing:
create three machines
install the application
start an instance on each
check which ones are alive
restart any that diedwe learned to write, conceptually:
there should be three healthy instances of this applicationand let something else work out the steps.
Kubernetes is the version most of us know. In the words of its documentation, “controllers are control loops that watch the state of your cluster, then make or request changes where needed. Each controller tries to move the current cluster state closer to the desired state.” A control loop, in the same page, is “a non-terminating loop that regulates the state of a system.”
Two design choices from that world are worth carrying over.
The first is that reconciliation is level-based, not edge-based. Kubernetes’ design principles put it precisely: the system “must operate correctly given the desired state and the current/observed state, regardless of how many intermediate state updates may have been missed. Edge-triggered behavior must be just an optimization.” A controller doesn’t need the story of how the cluster got here. It needs the declaration and a fresh look. For agents, that is the difference between work that can only continue from its own transcript and work any session can pick up cold.
The second is that there isn’t one big controller. “It’s useful to have simple controllers rather than one, monolithic set of control loops that are interlinked,” the documentation says. Many small reconcilers, each responsible for one part of the state. Hold on to that for when we get to hierarchy.
This is also where the analogy stops being comfortable. In infrastructure, the difference between desired and actual is usually something you can compute. Three replicas desired, two observed: the diff is one.
Now take “authentication is production-ready.”
Maybe Google sign-in works and password sign-in doesn’t. Maybe both work, but sessions don’t survive a reload. Maybe everything works and nothing is tested. Maybe the tests exist, but a development credential is sitting in the repository. Maybe it’s all fine, except nobody else could run it from the README.
There is no subtraction that produces that list. The gap has to be inferred.
Infrastructure: desired − actual = diff
Agents: desired − actual → inferred gapThat is exactly where agents become useful, and exactly where I want to be careful. I argued in AI Is Not Your Compiler that models are not deterministic translators of intent: “Compilers refuse. Models improvise.” A reconciler built on a model can infer the wrong gap, pick the wrong action, fix one thing and break another, and then describe the result with complete confidence.
Desired-state development doesn’t pretend otherwise. It keeps the declarative half of infrastructure as code and deliberately gives up the deterministic half. What replaces it is verification. Anthropic’s guidance on building agents makes the same point from the agent’s side: “it’s crucial for the agents to gain ‘ground truth’ from the environment at each step.” And in Skills, Pipes, and the Unix Philosophy I split the work three ways: the model decides, the program executes, the model checks. Desired state pushes one step further. Wherever a check can be a program too, make it one.
Desired-state development, defined
My working definition:
Desired-state development is a way of building software with agents in which the primary artifact is a declaration of what must be true, rather than a sequence of steps. A governing agent repeatedly observes the current state, infers the gap, delegates bounded work to execution agents, and reconciles until every declared condition is either backed by evidence or waiting on a human decision.
The important word isn’t agent. It’s reconcile.
flowchart TD
D[Desired state<br/>what must be true]
O[Observe<br/>repository, CI, running system]
G[Infer the gap]
W[Delegate bounded work<br/>coding harnesses]
E[Evidence<br/>tests, probes, artifacts]
C{Checked?}
A[Owner verdict<br/>claims no check can settle]
H[Hold the state<br/>watch for drift]
D --> O --> G --> W --> E --> C
C -- not yet --> O
C -- needs judgment --> A
A -- redirect --> O
A -- amen --> H
C -- satisfied --> H
H -. drift .-> O
classDef strong fill:#0A0A0A,stroke:#00FFFF,color:#E0E0E0
classDef weak fill:#0A0A0A,stroke:#666,color:#999
class G,E,C,A strong
class D,O,W,H weak
In plain text: the loop starts from the desired state and a fresh observation of the repository, CI, and the running system. A governing agent infers the gap and delegates bounded work to coding harnesses, and the work produces evidence: tests, probes, artifacts. A condition that isn’t met yet sends the loop back to observation. A satisfied one becomes a held state, watched for drift. Claims no check can settle go to the owner, whose verdict confirms them or redirects the loop. The highlighted boxes, inferring the gap, evidence, checking, and the owner’s verdict, are where this differs from a to-do list.
Three properties follow from that loop.
Declarative. The primary artifact says what must be true. The plan is derived from it, and the plan is disposable.
Level-triggered. Any agent, in any session, can pick up the work from the declaration and a fresh observation. The transcript is useful history, not a dependency.
Evidence-terminated. The loop ends because the checks pass and the owner agrees, not because an agent reports that it’s finished.
In Your Docs Are Not the Prompt I ended with a short ladder: “Prompts should define the task. Code should remain the source of truth. Tests should verify behavior.” I would add one rung: the desired state should define done. It doesn’t compete with the code as a source of truth. The code and the running system are the truth about what is. The declaration is the truth about what should be. Reconciliation is the work that happens between them.
A few neighbors already have names, and I’d rather be precise about the overlap.
Loop engineering is the closest. Osmani’s essay is about the machinery that keeps an agent working without a human prompting every turn: automations, worktrees, skills, connectors, subagents. His follow-up, Own the Outer Loop, draws the line I care about most: “Engineers own the outer loop.” Desired state is what I want that machinery to reconcile against. A loop without a declared state keeps prompting. A controller with one converges.
Spec-driven development is the other neighbor. Kiro writes requirements in EARS notation, WHEN [condition/event] THE SYSTEM SHALL [expected behavior], which is about as close to a desired-state assertion as a sentence gets. Its property-based tests are honest about what they give you: “It provides evidence of correctness, not a proof.” GitHub’s Spec Kit now ends its flow with a converge step: “Repeat implement → converge until convergence reports Converged.” Spec-driven development converges a feature. Desired state keeps asking after the feature ships.
Done is a claim, so decide who may change the state
I have argued in several posts that a completion message is not evidence. Latch turned that into a rule, DONE ≠ PASS, and Silhouette gave it my favorite phrasing: “Finished-looking is a rendering property. Locked is a decision property.”
I won’t make that argument again. Desired state forces a narrower and more useful question: who is allowed to move an assertion from not yet to satisfied?
The worst candidate is the worker. The agent that implemented a change has the most context about what it did and the least distance from it. It is also the one being judged.
A separate judge helps, and the tools are moving that way. But look at what the judge can see. Claude Code’s documentation is explicit that its goal evaluator “does not call tools, so it can only judge what Claude has already surfaced in the conversation.” A judge that reads the transcript is judging the story of the work.
A recent preprint on false success in LLM agents describes agents that “can fail silently by asserting task completion when the environment state shows otherwise,” and model judges that, asked to catch it, “rely on surface completion proxies,” such as confident closing language, “rather than verified state changes.” It is one paper, and I would treat it as one paper. But it describes exactly the failure I would expect when the evidence is a paragraph.
Anthropic ran into the same problem building harnesses for long-running agents, and its fix is the most desired-state thing I’ve read from a lab. An initializer agent writes a list of every feature, each with its verification steps, and every feature starts out failing: "passes": false. Later sessions may only change that field, under an instruction that leaves little room: “It is unacceptable to remove or edit tests because this could lead to missing or buggy functionality.” They did it because agents kept “prematurely considering the project complete.”
That list is a desired state in all but name. What I would change is who holds the pen. The rule I keep converging on has three parts:
- Deterministic checks change the state. Tests, type checks, builds, probes against a preview deployment, a secret scanner. If a program can decide it, a program decides it.
- Agent checks propose. A reviewer agent can read a diff against a design. A fresh agent can follow the README in a clean container and report where it got stuck. Their findings are evidence, and they can block. They don’t get to mark a judgment satisfied.
- The owner says amen. Whether a failure is easy to recover from, whether the architecture still matches the intent: those are judgments. In Silhouette, only the owner said amen, and I don’t see a reason to relax that for code.
Put together, a declaration looks less like a prompt and more like this. It is illustrative, not a file from one of my repositories:
desired_state: auth-production-ready
owner: me
assertions:
- id: auth.password
statement: Users can sign in with email and password
check: deterministic
evidence: end-to-end auth suite passes against the preview deployment
- id: auth.unauthenticated
statement: Unauthenticated API requests receive 401
check: deterministic
evidence: API probe against the preview deployment
- id: auth.secrets
statement: No credentials are committed
check: deterministic
evidence: secret scanner passes on the branch
- id: auth.setup-docs
statement: A new developer can run auth locally from the README
check: agent-proposes
evidence: a fresh agent in a clean container reaches a signed-in session
- id: auth.recovery-ux
statement: A failed sign-in makes recovery obvious
check: owner-amen
evidence: screenshots of every failure path
boundaries:
may_change: [apps/web/auth, packages/auth]
must_not_change: [billing, infrastructure]
needs_approval: [schema migrations, new dependencies]
escalate_when:
- an assertion needs a decision this file doesn't make
- two reconciliation rounds make no progressThis is also where the file problem from the beginning resolves. A goal that says “read this file” fails when the judge can’t read the file. It works when the thing deciding completion is the thing that runs the checks. In Claude Code, /goal is “a wrapper around a session-scoped prompt-based Stop hook,” and a Stop hook “can run a script for deterministic checks or a prompt for model-evaluated ones.” So the goal can stay short, far under any character limit, and point at the declaration, because the script at the gate reads that same declaration and runs its checks.
The pointer was never the problem. A pointer that the judge can’t follow was.
Structure follows resolution, not the org chart
When I first described this idea out loud, I reached for the obvious analogy: a software team. Someone holds the roadmap. A product manager turns it into goals for the quarter. A tech lead breaks those into work for the week. Developers take tasks to completion. Every layer is more granular than the one above it.
It turns out Scrum already had the vocabulary. The 2020 Scrum Guide gives each artifact a commitment. “The Product Goal describes a future state of the product which can serve as a target for the Scrum Team to plan against.” The Sprint Goal “is the single objective for the Sprint,” and it “provides flexibility in terms of the exact work needed to achieve it.” And “the Definition of Done is a formal description of the state of the Increment when it meets the quality measures required for the product.”
Read those again with this post in mind. A future state to plan against. An objective that is flexible about the work. A formal description of a state, with quality measures. Human teams have been running desired states at three resolutions for years. The backlog was always the plan, not the target.
What I don’t want to copy is the org chart. Early multi-agent research tried that literally, with virtual software companies of agents playing product managers, architects, engineers, and testers. The titles weren’t the interesting part. In MetaGPT, agents “communicate through documents and diagrams (structured outputs) rather than dialogue,” and the authors report that those intermediate outputs significantly increase the success rate. The artifacts carried the work. And agents don’t need ceremonies: a standup exists because fifteen people can’t share a context window.
The hierarchy I want is a hierarchy of resolution:
Product state "ready for public beta"
System state "authentication is production-ready"
Component "refresh tokens have integration coverage"
Change one bounded task in one repositoryEach level runs the same loop: observe, compare, infer, act or delegate, collect evidence, repeat. That makes it recursive. Tell a governing agent the product should be ready for public beta, and one unresolved condition it finds may be that authentication isn’t production-ready. That becomes a desired state of its own. Its reconciler discovers that refresh-token behavior has no integration coverage, and that becomes a bounded change small enough for any coding harness to take.
These are Kubernetes’ simple controllers rather than a monolith, with a model inside each one. It is also the property that made the stages in Silhouette work: “When a lower stage moves, everything above it has to be judged again.” Evidence travels up, and re-evaluation travels up with it.
Choose your altitude
We say a system should keep a human in the loop. Which loop?
The layers make that question answerable. When the work is converging cleanly, I can stay at the top, looking at the product state and the evidence that rolls up to it. When something looks off, I can descend: into the system design, into the plan a reconciler generated, into a single task, occasionally into a diff. Then I can climb back out.
At any layer, the same few interventions work:
Stop. Show me why this is the next step.
Show me the evidence, not the summary.
That assumption is wrong. Here is the constraint.
Let me take this one.
I wrote in The Back Office / Front Office Split that “a good assistant doesn’t eliminate work—they move you up the stack.” This is the engineering version of that. My involvement doesn’t disappear. It moves to where my judgment is worth the most, and I choose the altitude instead of the tool choosing it for me.
The verdict stays where it was. Silhouette’s own retrospective put it better than I can: “I can iterate all night. I cannot say so be it for you.”
Separate the control plane from the execution plane
Once there is a declared state, and layers of it, a second separation follows. The agent writing the code shouldn’t be the agent deciding what work matters next.
A coding harness is excellent close to the repository. Give it a bounded problem and it will explore, change code, run tests, read failures, and iterate. That is an execution role. It doesn’t need to own the roadmap, remember why a decision was made six weeks ago, or decide whether the release is ready.
The governing agent has a different job: observe, infer the gap, prioritize, dispatch, verify, and update the state. Its contract with a worker is short:
Here is a bounded change and the assertions it should satisfy. Work inside these boundaries. Change the environment, run the checks, and come back with evidence, not a summary.
Tasks come out of that loop. They are not what the loop reconciles. A reconciler should be free to decide that a task is no longer necessary, split one into five, discover one nobody wrote, or close one because another change already satisfied its intent.
Tasks should be generated by reconciliation, not mistaken for the thing being reconciled.
Pieces of this are already shipping. Claude Code’s Projects, in public beta on Pro and Max plans as I write this, is “one long-running session where Claude acts as coordinator,” starting a thread for each task. “It sees what threads report back, not every step they take.” A project can carry an optional one-line goal, and the example in the documentation is “Hold p95 API latency under 200 ms.” That isn’t a task. It’s a state to hold.
OpenAI’s open-source Symphony goes further into the vocabulary. Its specification says “Reconciliation runs before dispatch on every tick,” and it knows the thing I keep insisting on: “A successful worker exit does not mean the issue is done forever.” What Symphony reconciles, though, is the issue tracker: which tickets are active, which workers are running. The board is its desired state. I want the declaration one level above the board, so that the board becomes an output.
Two more things fall out of this separation.
The first is that choosing a model and choosing a role are different decisions. The governor and the worker can run on the same model and still be different agents, because they have different context, authority, tools, lifetimes, and definitions of success. I said in Harness-Driven Development that the same model in a different harness is a different engineer. The same model in a different role is a different engineer too. And governing is a skill of its own. LoopArena, a benchmark that isolates a controller model from a fixed coding agent, found that a loop “may trust a stale progress note, skip needed verification, spend its budget in the wrong direction, or stop before the task is safe to submit.” The best controller it observed reached a strict success rate of 24.69% on full tasks. Coding well and governing well are not the same capability.
The second is where the human sits today. Anthropic studied roughly 400,000 Claude Code sessions and found that “people make about 70% of the planning decisions but only 20% of the execution decisions,” where planning means “what to do, which approach to take, what counts as done.” Desired-state development doesn’t take that away from people. It writes the last part down. What counts as done becomes an artifact the owner holds, so that something other than the worker can check it.
It also adds an axis to a line from Harness-Driven Development: “‘Which harness owns this task’ is a real architectural question now.” So is which harness owns which layer of state. From where I sit, and from the outside for the tools I haven’t used much, they lean like this:
- Kiro is built around the specification layer: requirements, design, and tasks as files, with acceptance criteria written as assertions.
- Antigravity is a harness in the most literal sense. In Google’s own framing, “Gemini Flash is the LLM and Google Antigravity is the harness,” and its agent manager is designed for running several agents across workspaces.
- Codex is where I hold goals and coordinate local work, with sessions that can read and message each other.
- Claude Code is still very good in the repository, and its hooks can decide whether a session is allowed to stop.
- Grok Bot is where I keep durable bots with names and responsibilities.
That last point is the beginning of an answer to a question I left open in the Codex post: how an AI crew should be structured, which responsibilities should stay durable, and which should be created for a task. Desired state suggests a rule. The durable roles hold a layer of state. The temporary ones are spawned per gap and dissolve when the evidence comes back.
Which leaves the obvious question. If the coding agent shouldn’t hold the control plane, who should?
Personal assistants are becoming the control plane
For a long time, the obvious candidates were all wrong in some way. A coding agent lives too close to the implementation. A project board knows the tasks but not the intent behind them. A chatbot could help me think, but it didn’t persist, and it couldn’t act between conversations.
That is changing, and it’s changing from a direction I didn’t expect.
In Agent-First Development I used Instinct to show an assistant that doesn’t need an interface of its own. What matters here is a different part of it. Instinct describes itself as “a personal assistant that understands what you’re working on and what’s important to you,” and one of the things it lists is “following up on threads you’ve dropped.” It is a consumer assistant, not a development tool, though a well-funded one: TechCrunch reported a $1 billion round in September. What interests me is the shape. Continuity becomes the assistant’s job rather than yours: something keeps track of what you are trying to achieve, notices what has gone quiet, and acts without waiting for you to open a window.
OpenAI’s dots, launched at DevDay on September 29, are the clearest version of that shape so far. The help center describes a dot as “an always-on agent in ChatGPT that can take on ongoing responsibility and keep making progress between conversations.” It “has its own cloud computer, works across the apps you choose to connect, and remembers context to help with ongoing work.” And then the sentence that stopped me: “It can work through complex problems, figure out what needs to happen next, and bring results back for your review. It turns to you for decisions that need your judgment.”
That is almost a definition of a control plane, waiting for a domain.
The domain is already wired in. “Your dot can create cloud tasks in Codex cloud environments,” the same page says, and the announcement adds: “Over time, we envision teams of dots working together on your behalf.” Availability is still limited: dots are rolling out to Pro and Business Premium plans, and the Pro rollout excludes the European Economic Area, Switzerland, and the UK.
Anthropic got there from the other side. Dispatch is “a persistent conversation with Claude,” and when you message it a task, it can decide that “the task is development work” and start a Claude Code session on its own.
Grok Bot, where I already keep a small roster of bots, describes the company’s own people working this way. Its launch post talks about running several bots in parallel, “with one to manage the others. A chief of staff sits on top, with a specialist for each lane,” and bug fixes is one of the lanes it lists. “Bots can independently message each other.”
So the dispatch path exists. A persistent assistant can already hand work to a coding harness, at more than one lab. What’s missing isn’t another integration. It is the discipline: a declared state for the assistant to hold, a reconciliation loop that decides what to dispatch next, and evidence, not a worker’s summary, deciding when each piece is done.
flowchart TD H[Human<br/>intent, priorities, verdicts] P[Personal assistant<br/>desired state, memory, decisions] R[Reconcile<br/>observe, infer the gap, prioritize] X[Coding harnesses<br/>Codex, Claude Code, Kiro, Antigravity] S[Software<br/>repository, CI, running system] E[Evidence<br/>checks, artifacts, previews] H <--> P P --> R R -- bounded work --> X X --> S --> E --> R R -- status and questions --> P classDef strong fill:#0A0A0A,stroke:#00FFFF,color:#E0E0E0 classDef weak fill:#0A0A0A,stroke:#666,color:#999 class P,R,E strong class H,X,S weak
In plain text: the human talks with a personal assistant about intent, priorities, and verdicts. The assistant holds the desired state, the memory, and the decisions made so far. A reconciliation step observes, infers the gap, prioritizes, and sends bounded work to coding harnesses such as Codex, Claude Code, Kiro, or Antigravity. Their changes to the repository, CI, and the running system produce evidence, which flows back into reconciliation, and reconciliation reports status and questions to the assistant. The highlighted boxes, the assistant, reconciliation, and evidence, form the control plane.
There is a quieter benefit here. A lot of effort, mine included, goes into making long-running coding sessions remember everything, and I’m increasingly convinced it’s the wrong goal. The persistent layer should hold intent and state. The execution layer should receive what the next transition needs. The assistant might know a hundred things about a project: why a decision was made, what matters to me this month, which approach we rejected. The worker needs eight of them, plus the assertions, the boundaries, and the repository. Context gets compiled downward, per task, instead of accumulating forever in one enormous conversation.
It also makes the work asynchronous in a way that feels natural. An illustrative morning, not a transcript:
08:00 Assistant observes: PR #31 merged, CI green, #44 unblocked.
auth.refresh-tokens still has no integration coverage.
08:02 Dispatches a bounded change to a coding harness,
with the assertion and the boundaries attached.
08:40 Worker returns new tests, a CI run, and links.
08:41 Checks pass. The assertion flips to satisfied.
auth.recovery-ux is still waiting for my review.
08:42 Assistant picks the next gap and queues one question for me.I don’t have to be the integration between those steps. I can still step into any of them.
None of this means handing an assistant unlimited authority and a slogan. If the instruction is “keep working until the state is true,” and the agent decides both what true means and what it may do to get there, we have built a machine that can rationalize its own completion.
The declaration has to carry its limits: what may change, which systems can be touched, which actions need approval, which checks need a person, when to stop, and when to escalate. The products are drawing some of these lines already. Grok Bot’s documentation is explicit that all your bots share one computer: “Do not use separate Bots as a security boundary.” OpenAI says of dots that “Certain sensitive tasks, such as changing a password, always stay with you,” and that “Dots can still make mistakes, so always review consequential work.” And the failure I described in Harness-Driven Development applies at this altitude too: the over-permissioned agent that will pursue a vague objective “with the confidence of a system that has never been embarrassed.”
The reconciler needs authority. That authority should be scoped, and the scope belongs in the declaration.
Try it on one repository
You don’t need an assistant platform to start. One repository and two sessions are enough.
- Write the state, not the plan. A file of assertions, each with a check and a check type: deterministic, agent-proposed, or the owner’s amen. Add the boundaries and the escalation rules.
- Keep the goal a pointer. Something like reconcile the declaration in this file, and stop when every deterministic check passes and the rest are waiting on me. Short enough for any goal box.
- Make the gate read the file. Wherever your harness lets a script decide whether a session may stop, have that script run the declaration’s checks. Don’t ask a judge to verify what it can’t see.
- Separate governing from doing. Run the reconciler in one session and give workers bounded changes in others. Workers return evidence. Only the checks, and you, change the status.
- Throw the plan away freely. The task list is the reconciler’s current hypothesis about how to close the gap. When the evidence changes, generate a new one. Kubernetes doesn’t mourn a pod.
- Choose your altitude in advance. Decide which assertions you want to see evidence for as it lands, and which you’ll only look at when the loop stops converging.
Then watch what the unit of work becomes. For a while, the unit of AI-assisted development was the prompt. Then it was the task. I think both are transitional. The more durable unit is a justified state transition:
S0 ── evidence-backed change ──▶ S1 ── evidence-backed change ──▶ S2 … desired stateWe were here. We wanted to be there. This work happened, and here is the evidence that reality moved closer. That record outlives a transcript, which matters, because as I wrote in the Codex post, the conversation “should not become the only place where the project exists.” And when the world changes afterward, whether it’s a dependency, a requirement, or a regression, we don’t declare the old goal finished and write a new one. We reconcile again.
Infrastructure engineering taught us to stop describing every step and start declaring what should be true. Agents let us carry that idea much further up the stack, into the part of software development where the gap has to be understood before it can be closed.
Describe the state. Observe reality. Infer the gap. Reconcile until the evidence, not the agent, says we’re there.
That is what I mean by desired-state development.
Further reading
Sources that shaped this post beyond the ones linked above, chosen because they should stay useful as the products change:
- OpenGitOps, the four principles, the last of which is “Continuously Reconciled.”
- Microsoft, Desired State Configuration, which keeps checking whether a resource is in its desired state separate from enforcing it.
- CFEngine, Mark Burgess’s convergent configuration engine from 1993, and HashiCorp’s terraform plan, the deterministic diff at its most familiar.
- OpenAI, Using Goals in Codex, which puts it plainly: “completion must be evidence-based.”
- Claude Code, agent teams and routines, whose documentation is candid that a lead “can stop early” and that a green run “does not mean the task in your prompt succeeded.”
- Research on evidence-gated completion: Verify-Gated Completion as Admission Control and Proof-or-Stop. And a single, fully instrumented case study with an explicit convergence rule: Specification-first convergence with an AI coding agent.
- ChatDev, a chat-powered virtual software company of agents, for contrast with MetaGPT’s documents.
- Geoffrey Huntley, Ralph, the loop that runs the same prompt again and again until the work is done.
- Other routes from a conversation to a coding agent: OpenClaw, a self-hosted gateway from messaging apps to coding agents, and Codex in Slack.
Dictated by voice, developed in a conversation with GPT, then researched, drafted, and published with Claude Code. The arguments are mine; the drafting was collaborative.