When your buyer says "agentic AI," they almost always mean a model that calls tools. Two components do the work: the model(which emits a structured request and stops) and the harness(which carries a credential, executes the call, handles the error, and returns the result). You will encounter this split the moment a buyer describes what their engineering team is building, and the precise language to distinguish model-side from harness-side is what keeps you from bluffing through the identity part of that conversation. Credential questions, blast-radius questions, "who authorized this action" questions: they all live on the harness side. The model is the decision. The harness is the consequence.
One scope note: this piece covers the single-turn loop, meaning one complete cycle. Model emits a tool-call request, harness executes it, result comes back, model responds. That's the unit. When many of these cycles chain together, context accumulates, tokens degrade, and a different set of problems emerges. That's 5.7. Here, we're inside one turn, looking at the plumbing.
Subject Profiles
Model
What it is: The large language model (GPT-4o, Claude, Gemini, etc.) that receives a prompt and tool definitions, then either generates prose or emits a structured tool-call request.
What it does: When the model determines a user's request requires a tool, it stops generating text and outputs a JSON object containing a tool name, arguments, and a correlation ID. Anthropic's tool-use documentation shows the actual output:
{
"type": "tool_use",
"id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
"name": "get_stock_price",
"input": { "ticker": "^GSPC" }
}Three meaningful fields. The model executes nothing. It touches no system. It holds no credential. It emits a request and waits.
Who's behind it: The model provider — OpenAI, Anthropic, Google, Meta for open-weight models. The wire format varies by provider (OpenAI encodes arguments as a JSON string that the harness must parse; Anthropic returns a parsed object), but the principle is identical across all of them.
What makes it distinct: The model is probabilistic. It picks the tool and constructs the arguments based on pattern-matching over its context window. No rule engine, no policy lookup, no formal guarantee it picked correctly. It's making its best guess, expressed as JSON. Two beers in, the way to think about it: the model is the person who says "we should call facilities." It doesn't pick up the phone.
Harness
What it is: The developer-built infrastructure (sometimes called the scaffold or orchestrator) that wraps the model, manages the conversation loop, and executes tool calls on the model's behalf.
What it does: The full list of consequential actions in the loop. The harness assembles the context sent to the model. It receives the model's tool-call request, validates the arguments against the tool's schema, injects the appropriate credential, executes the actual API call or database query, handles any error, formats the result, and sends it back to the model as a tool_result message. It also decides what happens when things go wrong: retry, circuit-break, or surface the error to the user.
Who's behind it: The buyer's development team. This is custom code. It might be a Python script, a cloud function, an orchestration framework like LangChain, or a managed service. The harness is where the engineering team's decisions live and where the organization's security posture is actually expressed.
What makes it distinct: The harness is deterministic. It runs code, not inference. It carries the credential. It controls the blast radius. If the model picks the wrong tool, the harness is the thing that either catches the mistake or executes it with real consequences against a real system using a real identity. Two beers in: the harness is the person who actually dials the number, uses their badge to get into the building, and deals with whatever happens next.
Phase by Phase Through the Single-Turn Loop
Comparison strategy: I'm walking through one complete tool-call cycle in five sequential phases. This is the most efficient structure because the model and harness take turns acting, and the failure modes land at specific, identifiable phases. Each phase has exactly one active component. The other is either waiting or absent entirely. The dimension is model-side vs. harness-side; the failure modes are harness-observable problems with structured, inspectable outputs.
Phase 1 — Context Assembly
The harness acts. The model waits.
The harness constructs the full prompt: system instructions, conversation history, tool definitions (name, description, input schema for each available tool), and the user's current message. This assembled context is the only reality the model will ever see. The harness decides which tools are visible, how they're described, and what prior conversation is included.
A poorly named or ambiguously described tool causes failures in Phase 2 that look like model problems but were authored here. Both Anthropic and OpenAI recommend prefixing tool names with the service (github_list_prs, slack_send_message) to prevent selection ambiguity as the tool library grows. BFCL research confirms this holds across models, not just one provider's. A harness-side configuration choice shaping model-side accuracy.
Tool definitions also consume tokens. Anthropic's documentation notes that the API constructs a special system prompt from tool definitions, tool configuration, and any user-specified system prompt. More tools means a larger context payload, which means higher cost and less room for conversation history. The harness decides this tradeoff.
Phase 2 — Tool Decision
The model acts. The harness waits.
The model processes the assembled context and decides: respond with prose, or emit a tool-call request. If it chooses a tool, it outputs the structured JSON. The model's stop signal changes (Anthropic returns stop_reason: "tool_use"; OpenAI returns finish_reason: "tool_calls"), telling the harness that execution is expected.
Three of the four common failure modes originate here, and all three produce structured data the harness can inspect before anything runs:
Wrong tool selected. The model picks search_email when it should have picked search_calendar. The harness can detect this post-execution (the result won't match expectations) but not pre-execution unless it implements intent-validation logic.
Hallucinated tool name. The model invents a tool that doesn't exist in the registered set. The harness catches this instantly — the name isn't in the tool list. No execution needed.
Bad arguments. The model calls the right tool but constructs arguments that don't match the schema, or fills a required field with a hallucinated value. BFCL research documents a specific pattern worth knowing: models frequently skip a prerequisite call (like list_keys to see what's available) and guess at an argument value instead. The harness executes with the guessed value, gets an error back, and many models give up after a single failure rather than retrying correctly. The failure is visible at every step. The model's guess is in the JSON. The error is in the result. The premature quit is in the next stop_reason.
So what does rejection look like in practice? When the harness catches a hallucinated name or a schema violation, it has two options. It can send back a tool_result with is_error: true and a descriptive message, which keeps the agent loop running and gives the model a chance to correct itself. Or it can terminate the loop entirely and surface the failure to the user. Anthropic's Claude Code SDK is explicit: when the handler returns an error result normally, the agent loop continues. The harness decides whether a bad call is recoverable.
The thing to carry into buyer conversations: these failures are structured data. The harness receives a JSON object it can inspect, validate, and reject before anything touches a production system.
You already know this split from zero trust. The model behaves like a Policy Decision Point: it evaluates context and emits a decision. The harness behaves like a Policy Enforcement Point: it takes that decision and acts on it. The analogy holds structurally. Where it breaks: a PDP consults a policy store with defined rules and produces a deterministic result. The model consults a context window and produces a probabilistic guess. And most harnesses today enforce nothing except the tool schema — there's no policy store, no re-check. The "PEP" just runs whatever the "PDP" asked for, with whatever credential it was configured to carry. That gap is the conversation.
Phase 3 — Execution
The harness acts. The model is gone. It has no awareness that execution is happening.
The harness takes the tool name and arguments, injects the credential, and makes the actual call: an API request, a database query, a file operation. The identity question lives here, fully and plainly.
Anthropic's published production pattern stores OAuth tokens in a secure vault. A dedicated proxy fetches the credential per-call and makes the request to the external service. The model never sees the token. The harness never holds it in memory. (This architecture is described in Anthropic's "Scaling Managed Agents" engineering post from April 2026.)
What you'll actually hear from buyers is closer to "we use a service account with an API key." That's the more common and more dangerous pattern: a long-lived credential configured at harness startup, scoped broadly enough to cover every tool the agent might conceivably call. The blast radius is the service account's full permission set, regardless of which specific tool the model requested or whether the user who initiated the session should have access to that particular resource.
This is the privileged access problem your buyer already understands, wearing different clothes. An over-scoped service account running tool calls is functionally identical to a shared admin credential running scripts. The remediation is the same: least privilege, short-lived tokens, per-resource scoping. Here, the entity requesting the action is a probabilistic model that might request the wrong action. The credential doesn't know the difference.
Phase 4 — Observation
The harness acts again. It takes the raw result from execution, formats it, and sends it back to the model as a tool_result message, keyed to the original correlation ID.
What the harness returns here has outsized impact on what happens next. Anthropic's documentation is explicit: return only high-signal information. Return semantic, stable identifiers rather than opaque internal references. A 50KB raw database dump wastes context. A generic "Failed" error message gives the model nothing to work with. A precise error like Error: user_id 'jsmith' not found in directory lets the model reason about what went wrong.
The fourth failure mode lives in this phase: misinterpreted observation. The model receives the result and draws the wrong conclusion. Maybe the API returned an empty array (meaning "no results") and the model interprets it as an error. Maybe the result contains an ambiguous status code. The harness controls the shape of what the model sees. Better formatting produces better model reasoning. A harness-quality problem that the team will spend three hours debugging on the model side.
Phase 5 — Response
The model acts. It takes the tool result now sitting in its context window and generates a natural-language response to the user, or decides to call another tool. If it calls another tool, the loop restarts at Phase 2. When many of these loops chain together across a session, context accumulates and a different set of problems emerges — that's 5.7.
The harness is passive here but still observing. If the model's response contradicts the tool result, or if the model claims the tool returned something it didn't, the harness has the ground truth in its own logs.
| Phase | Model does | Harness does | Failure mode |
|---|---|---|---|
| Context Assembly | Nothing | Builds prompt, selects tools, sets descriptions | Ambiguous tool names, missing descriptions → downstream selection errors |
| Tool Decision | Emits JSON: name, args, ID | Waits for stop signal | Wrong tool, hallucinated name, bad arguments — all in the JSON |
| Execution | Nothing (not even aware) | Injects credential, makes the call | Over-scoped credential, permission denial, network failure |
| Observation | Nothing | Formats result, returns tool_result | Bloated or ambiguous result → model misinterpretation |
| Response | Generates text or next tool call | Logs and validates | Model contradicts tool result; harness holds ground truth |
In OAuth, short-lived access tokens exist because permissions change. A token issued at 9 AM shouldn't still work at 5 PM if the user's access was revoked at noon. Tool-calling harnesses have the same problem. OWASP's Agentic Top 10 (2026) names it explicitly: TOCTOU (Time of Check / Time of Use) errors, where authorization is checked once at session start and never re-verified mid-session. Your buyer already solves this with token expiry and refresh flows. The question is whether their agent infrastructure does the same.
How to Say This in the Field
| Don't say | Do say | Why it matters |
|---|---|---|
| "The AI agent calls your APIs" | "The model emits a request. The harness calls your APIs with a credential it carries." | Separates the decision from the consequence; buyers need to know where the credential lives |
| "The model executes tools" | "The model produces JSON — a tool name and arguments. It executes nothing." | Prevents the buyer from thinking the model has system access |
| "AI agents need access controls" | "The harness carries the credential. The scope of that credential is the blast radius." | Connects to PAM and least privilege, which the buyer already owns |
| "Tool calling is unpredictable" | "The model's tool selection is probabilistic, but the output is structured JSON you can validate before execution." | Grounds the risk in engineering the buyer can act on |
| "Agents can hallucinate tool calls" | "The model can emit a tool name that doesn't exist. The harness catches that before anything runs." | Makes the failure concrete and the mitigation obvious |
| "We need to secure the AI" | "Scope the credential the harness injects, the same way you'd scope a service account." | Maps to existing buyer practice |
| "The agent makes decisions" | "The model makes a recommendation in JSON. The harness decides whether to execute it." | Reframes agency; the harness is the enforcement point |
| "Tool calling errors are a model problem" | "Wrong tool, bad arguments, hallucinated names — all visible in the structured output before execution." | Makes failures harness-observable and diagnosable |
| "AI needs its own identity" | "The agent's identity is the credential the harness carries. Today, that's usually a service account." | Grounds the abstract in something the buyer can audit right now |
| "Agentic AI changes everything" | "The loop is: model emits request, harness executes with a credential, result goes back. The identity questions are on the harness side." | Gives the buyer a mechanical model instead of a buzzword |
Things to follow up on...
- OWASP's agentic risk taxonomy: The OWASP Top 10 for Agentic Applications (2026) names tool misuse (ASI02) and identity/privilege abuse (ASI03) as distinct risk categories, with specific attack patterns around cached credentials and delegation chains worth reading alongside this piece.
- Berkeley's function-calling benchmarks: The BFCL V3 multi-turn evaluation documents how models behave when tool calls fail mid-sequence, including the "guess and give up" pattern where models skip prerequisite calls and abandon tasks after a single error.
- Anthropic's vault-and-proxy credential pattern: Anthropic's engineering post on scaling managed agents details how their production systems isolate OAuth tokens from both the model and the harness using a dedicated proxy, which is the clearest published example of least-privilege credential injection for tool calls.
- MCP authorization is still moving: The MCP specification's authorization requirements have changed substantially between the 2024-11-05 and 2025-06-18 versions, adding OAuth 2.1 requirements for HTTP transports that didn't exist at launch.

