There are two ways to direct an agent. You can script the steps it takes, or you can lock the outcome and let it find its own way there. Almost everyone starts by scripting. Almost everyone should stop.

Thesis: The highest-leverage way to direct a capable agent is to specify the what and the why, then refuse to specify the how. Every step you script is a ceiling you impose. Bounding an agent with an outcome and a reason gives it room to be smarter than your instructions — and to get smarter as the model underneath it improves.


This is Post 1 of the "Intent Over Instructions" series — on directing agents by outcome instead of by procedure.

The Burger Test

Here's the whole principle in one sentence, courtesy of a colleague:

If I want a burger (what), because I'm hungry (why), I don't care how — just get me a f*cking burger.

You don't tell the kitchen which knife to use. You don't specify the order the vegetables get sliced, or whether the patty is flipped once or twice. You state the outcome (a burger), you carry a reason (hunger) that lets the kitchen resolve ambiguity — no bun? hunger says the food matters more than the form; make it a lettuce wrap — and you leave the method to the entity that actually knows how to cook.

Now watch what happens when people prompt an AI agent. They write the recipe. Step one, read this file. Step two, grep for that pattern. Step three, if you find X, do Y. They script every knife stroke — and then wonder why the agent feels rigid, brittle, and somehow dumber than it was in the chat window.

It's dumber because you made it dumber. You replaced its judgment with yours.

What, Why, How

Three layers sit inside every instruction you give an agent. Most people collapse them into one blob of prose. Pulling them apart is the entire game.

flowchart TD
    subgraph collapsed["The usual prompt: one collapsed blob"]
        Blob["'Read config.json, then loop over<br/>the services, and for each one check<br/>if the port is set, and if not add 8080,<br/>then write it back, and log what changed...'"]
    end

    subgraph layered["Bounded: three separate layers"]
        What["WHAT — the outcome<br/>'Every service has a valid port'"]
        Why["WHY — the reason<br/>'Services silently fail to bind without one'"]
        How["HOW — the method<br/>(the agent decides)"]
        What -.- Why
        Why -.- How
    end

    style Blob fill:#9d4444,color:#fff
    style What fill:#2d6a4f,color:#fff
    style Why fill:#2d6a4f,color:#fff
    style How fill:#5a5a8a,color:#fff
  • What is the outcome — the state of the world when the work is done. "Every service has a valid port." It is checkable. You can look at the result and say yes or no.
  • Why is the reason the outcome matters — "services silently fail to bind without one." The why is not decoration. It is what lets the agent resolve the hundred small ambiguities your what didn't cover. Which port? The why tells it the goal is binding, not a specific number, so any free valid port works.
  • How is the method — read the file, parse it, iterate, write it back. This is the part you should almost never write, because it is the part the agent is best at and the part most likely to be wrong tomorrow.

When you script the how, you are asserting that your method is better than whatever the agent would have chosen. Sometimes it is. Usually, on a capable model, it isn't — and even when it is today, it won't be after the next model release.

Overguiding Is Lossy

Scripting feels safe. It feels like control. But a scripted procedure is a lossy compression of your actual intent, and the agent decompresses it back into behavior that's missing everything you didn't say.

Consider the difference in how an agent handles the unexpected:

flowchart TD
    Start["Agent hits an unforeseen case<br/>(a service with a port range, not a single port)"]

    Start --> Scripted
    Start --> Bounded

    subgraph Scripted["Overguided: only has the HOW"]
        S1["Step 3 said 'if port is not set, add 8080'"]
        S1 --> S2["A range isn't 'not set'...<br/>but it isn't a single port either"]
        S2 --> S3["Follows the letter: overwrites the<br/>range with 8080. Breaks the service."]
    end

    subgraph Bounded["Bounded: has the WHAT + WHY"]
        B1["Goal: every service has a valid,<br/>bindable port. Reason: avoid silent<br/>bind failures"]
        B1 --> B2["A range is already bindable<br/>→ the goal is met"]
        B2 --> B3["Leaves it alone. Moves on."]
    end

    style S3 fill:#9d4444,color:#fff
    style B3 fill:#2d6a4f,color:#fff

The scripted agent has nothing to reason from. When reality steps outside your steps — and it always does — all it can do is follow the letter of an instruction that no longer fits. The bounded agent has the goal and the reason, so it recognizes a case you never enumerated and handles it correctly. Not because it's clairvoyant. Because you gave it the thing it needed to think with.

This is the counterintuitive part: the less procedure you specify, the more robust the agent gets. Procedure covers the cases you thought of. Intent covers the cases you didn't.

What You Actually Owe the Agent

"Don't specify the how" does not mean "throw a vague wish over the wall." A burger order still has a spec — it's just a spec of the outcome, not the method. Bounding is precise. It's precise about the right things.

You owe the agent three things, and the how is not one of them:

You owe it You don't owe it Why
The outcome (what "done" looks like) The procedure to reach it The agent picks a method; you judge the result
The reason (why it matters) Which tool to use at each step The why resolves ambiguity the what left open
The bar (how "done" is checked) The order of operations A checkable bar lets you verify without watching

Notice the third row. The most important thing you can hand an agent along with the outcome is a way to check the outcome — a "done when" it can hold itself against. This is why good agent skills increasingly read like exit criteria instead of recipes. A skill I work with defines each phase not as a list of steps but as a Goal and a Done when — the bar the agent has to clear — and at most a one-line hint about approach. The agent supplies the steps. The skill supplies the standard.

Same task, two shapes:

# Overguided — a recipe
1. Open the file with fs.readFile
2. JSON.parse the contents
3. Loop over the `services` array
4. For each, check `.port`
5. If undefined, set it to 8080
6. JSON.stringify and write back
7. console.log each change

# Bounded — a goal and a bar
Goal:      Every service in the config can bind on startup.
Why:       A missing port makes the service fail silently in prod.
Done when: Re-running the binder reports zero services without a
           valid, non-conflicting port — and no service that was
           already valid got changed.

The second one is shorter, and it's more specification, not less — because it specifies the thing that actually matters (the checkable end state) and drops the thing that doesn't (your guess at the method). It also happens to be readable by a human reviewer, a second agent, or the same agent six months from now on a better model.

Why This Compounds With Model Releases

Here's the payoff that makes bounding more than a style preference.

A scripted prompt is pinned to the capability of the model it was written for. You wrote those seven steps because, at the time, the agent needed hand-holding through them. When a stronger model arrives, the steps don't get better — they get in the way. The new model would have found a cleaner path, but your script forbids it. Your instructions become technical debt that actively suppresses the capability you're paying for.

flowchart LR
    subgraph scripted["Scripted prompt"]
        direction TB
        M1["Model v1"] --> P1["7 hand-holding steps"]
        M2["Model v2 (smarter)"] --> P2["Same 7 steps<br/>now a straitjacket"]
        P2 --> Ceiling["Capped at v1-era behavior"]
    end

    subgraph bounded["Bounded prompt"]
        direction TB
        N1["Model v1"] --> G1["Goal + why + bar"]
        N2["Model v2 (smarter)"] --> G2["Same goal + why + bar"]
        G2 --> Rise["Finds a better path.<br/>Behavior improves for free."]
    end

    style Ceiling fill:#9d4444,color:#fff
    style Rise fill:#2d6a4f,color:#fff

A bounded prompt is different. The goal, the reason, and the bar don't age — "every service can bind" is as true and as checkable on the next model as on this one. So when the model gets smarter, the how gets better underneath a spec that never changed. You wrote the instruction once; every model release upgrades it for free.

That's the deeper reason to bound instead of script. It's not only that bounded agents handle surprises better today. It's that bounded intent is the only kind of instruction that rides progress instead of fighting it. (That's the whole subject of the next post: instructions lean enough to outlive the model that inspired them.)

Where the How Still Belongs

Bounding is the default, not an absolute. There are cases where you genuinely do owe the agent a method:

  • Hard constraints with legal or safety weight. "Never log the raw SSN" is not an outcome to optimize toward — it's a rail. Rails are how, and they belong in the prompt.
  • A specific method is the requirement. If the task is "demonstrate the O(n) approach specifically," then the how is the what. Fine.
  • Non-obvious, load-bearing gotchas. "This API silently truncates batches over 500" is knowledge the agent can't derive from the goal. Hand it over — but as a fact about the terrain, not a step in a recipe.
  • Genuinely weak or narrow models. A small local model may need the scaffolding. Just know that the scaffolding is a tax you're paying for a capability gap, and revisit it when you upgrade.

The test for whether a how belongs in the prompt: would a smart, well-briefed contractor need to be told this, or would telling them insult them and box them in? Tell them the SSN rule. Don't tell them which knife to use.

What to Do Next

  • Split your next prompt into what / why / how. Write the three layers as three separate things. You'll usually find the how paragraph is the longest — and the first thing you should cut.
  • Delete the how and replace it with a bar. For every "then do X, then do Y," ask: what checkable end state was that trying to produce? Write that instead, as a "done when."
  • Always include the why. It's the cheapest token you'll spend and the one that resolves the most ambiguity. If you can't state why the outcome matters, you don't understand the task well enough to delegate it.
  • Re-read your prompt as a straitjacket. Ask: if the model got twice as smart tomorrow, would this instruction help it or cage it? Cut whatever cages it.
  • Keep the rails, drop the recipe. Safety and legal constraints stay. Your guess at the implementation goes.

Next in the series: Instructions That Outlive the Model — why the leanest, most generic instruction is usually the most durable one. Related: The Multi-Agent Illusion and Designing Agent Personas That Actually Work.