Skip to main content

The Model Is an Input

Alex Blom

On Microsoft's FY26 Q4 earnings call on July 29, Satya Nadella described the architecture we set out to build Tasks around: "we are building a new model system, where the harness, context, memory, and action space are separate from any one model family... every model is substitutable." Asked to expand, he put it plainly: "you've got to keep your harness separate from the model... any given model at any given time is swappable."

We didn't start here because Microsoft did. We built Tasks on this a while ago: run a deterministic process from your own code, and call a model only at the steps that need judgment, so the model is a part you can swap, not the thing the system is made of. It has been reassuring to watch the largest software company on earth land on the same design and say it out loud on an earnings call.

It isn't only Microsoft, either. Patrick Boyle makes the investor's version: the open models are good enough and far cheaper, so "the economic benefits of all this AI productivity would instead flow to the people using the models, rather than the company spending billions of dollars to build them." Sam Altman puts the cost of a given level of AI falling about 10x a year; a16z calls it LLMflation. The direction is settled. Nadella's phrase is the one that sticks: "the models are an input, not some extraction of the knowledge of the enterprise."

Why we build it as a task, not an agent

There are two ways to put a model to work. An agent takes a goal and decides its own path: what to call, in what order, when to stop. It's powerful for open-ended work a person is steering, but it chooses the path fresh on every run, so what it does (and what it costs) changes from one run to the next. A task is the other shape. Your code owns the process, the loops, the branches, and the order, and calls a model only at the bounded steps that need one.

The same job makes the difference concrete. Ticket triage, written as a task:

issues = aisle.integrations.jira.search_issues("status = Open AND team IS EMPTY")

for issue in issues:
    # the one step you couldn't code before: which of 12 teams is this?
    triage = aisle.ai.run_prompt(slug="triage-issue", variables={"issue": issue})
    aisle.integrations.jira.update_issue(
        issue["key"], team=triage["team"], priority=triage["priority"],
    )

The loop, the query, and the update are code you can read and run in your head. Only the classification in the middle goes to a model. Here is the same job handed to an agent instead, written as the instruction you'd give it:

Go through our open Jira issues that have no team assigned. For each one, read it, decide which of our twelve teams should own it and how urgent it is, then update the issue. Keep going until everything is triaged.

Oh, and if an issue looks like a duplicate, link it to the original instead of assigning a team. If you can't tell which team owns it, drop it in the triage backlog with a short note on why. Skip anything already assigned, don't touch closed issues, and if something looks like an outage, mark it urgent and post a heads-up in the incidents channel.

Both do the same work. The difference is where the process lives. In the task it's written down: the order is fixed, every rule is a branch you can read, diff, and test, and the only thing left to the model is the one judgment in the middle. In the prompt the process lives in the model's head. It re-reads that paragraph and re-decides the whole path on every run, so the order it works in, which rules actually fire, and how many tokens it burns can all shift from one run to the next. When it does something you didn't expect, there's no line to point at, because you never wrote one. That's the reliability argument we've made before, put as plainly as it goes: a task runs the steps you wrote, an agent decides the steps each time.

Your IP lives in the code, not the model

The valuable part of that task is the part you wrote: the sequence, the rules, the prompts, the fixes you added the first ten times it broke. That's ordinary code, and it's yours. The model is a component inside it, not the thing the asset is made of. A system that works becomes IP the company owns, and it doesn't walk out the door when a provider changes its terms.

That's also what makes "every model is substitutable" true for you and not just for Microsoft. Each step names its own model, so a better or newer one is a one-line edit, and the logic around it doesn't move. Your capability doesn't live inside a model you rent; it lives in code you own and can point at whichever model is best this quarter. When the frontier shifts, your system is unchanged and you decide whether to switch.

The cost is known before you ship

Because the process is defined in code, you know where every model call is before you ship, so you can price the run instead of discovering the bill. An agent's cost moves with the path it picks; a task's cost is the calls you wrote, times how many items you run them over.

It also gives you somewhere to act when prices move, and they move both ways: cheaper across the frontier over time, and more expensive at the top of a given model's life. You put the frontier model on the one step that needs it and smaller, cheaper models on the steps that don't, and you change that mix without touching the rest of the line. Nadella's own examples on the call were smaller models delivering "comparable quality... at significantly lower cost" on common work; Amy Hood called model diversification "a margin improvement opportunity" outright.

What a task gives you

Once the process is code and the model is one step inside it, the day-to-day follows:

  • It's easy to change. Real loops, branches, and functions: reviewable, versioned, diffable. You adjust a rule by editing a branch, not by re-wording a prompt and hoping. Your team maintains it like any other software.
  • The tests are separate from the model. A tests.py rides with the task, and mocks are the default, so a test never makes a real call or spends a token. You assert against your own functions, not the model's mood, which is what makes swapping a model safe rather than just possible: you prove the process still runs before you change what's underneath it.

The model is an input

It's encouraging to watch more companies build this way, but it isn't new to us. Keeping the work in code you own, with the model as a swappable part, has been the ethos from the start. Our own move from workflows to Tasks was a step in the same direction: put the process in code you own, with the model as one part of it. Write the process down, keep the model to the steps that need judgment, and you can swap it, price it, and test around it without the system changing underneath you. That's what it means to treat the model as an input, and it's what we built Tasks to do.

Stay in the loop

Product updates, tutorials, and AI insights. No spam.