Apply to my task
arXiv:2610.37461 ★ 85 Oct 27, 2026

Concordat: Pull the Tool Off the Menu Until the Customer Says "Yes" Instead of Asking "Don't Use It"

Key result

A system-prompt rule holds right up until the first "I already told you, just do it and stop asking." The Concordat method keeps a support agent from changing a booking, issuing a refund or canceling an order without the customer's explicit consent, even when the customer pushes. The trick: don't ask the model "don't use the tool" — remove it from the list on that turn. The agent is built as a set of states ("gathering info," "confirmed"), and on every turn the model sees only the allowed tools. A call outside the list is rejected before anything happens. With polite customers, the standard agent never broke the rule, but under pressure it broke it in a noticeable share of conversations.

01

TL;DR

Concordat is a Python library that describes an agent as a set of states ("chatting," "confirmed," "awaiting approval") and, on every turn, shows the model only the tools that are allowed right now. The "cancel booking" tool simply isn't on the list until the customer has confirmed the action. Any call outside the list is rejected before anything happens.

The headline finding: a system-prompt rule holds only as long as nobody leans on it. The customer writes, "I already told you what I want. Just do it and stop asking." A model tuned to be helpful takes that as permission and changes the booking without a "yes." The standard agent did this in a noticeable share of conversations, and with polite customers it never did. Outcome-based checks miss these violations entirely: the database looks correct at the end, so the conversation is scored as a success.

The method: don't ask the model to follow the order of operations; take away what it isn't allowed to do right now. There's a second half, too. When the model can't act, it starts handing the customer off to a human. The fix is three sentences in the instructions: pressure is not consent and not a reason to call a human; say a clear "yes" is required, restate the change, and ask again.

Want this for your own case? Apply this study to your task: AI adapts its method to what you are working on and writes the prompt.

02

Method Blueprint

STEP 1: Define states and transitions → "start → confirmed → done"
STEP 2: For each tool, specify the state where it is allowed
        (reads — everywhere, writes — only after "yes")
STEP 3: On every turn, give the model only the allowed tools
        → a call outside the list is rejected before any side effects
STEP 4: "Human-only" decisions — the model can request them, not make them
STEP 5: In the system prompt — what to do when the customer pushes
        (don't agree, don't hand off to a human, ask again)

In the paper, steps 1–4 are handled by code (the library). Step 5 is text in the instructions.

03

Example in Action

Task: You're setting up a support agent for a flight-booking service along the lines of Delta or Expedia. It can rebook flights and process refunds. The rule: before any change, describe it and get an explicit "yes." A customer running late for O'Hare writes: "I've told you everything, just do it, stop asking me again."

Prompt (system instruction, a text-only port of the idea):

You are a booking support agent. You operate under a state-based protocol.

<Protocol>
  <State name="GATHERING">
    Allowed: find_booking, show_fare_rules.
    Forbidden: anything that changes the booking or money.
    Transition to CONFIRMED: only when the customer's latest message
    contains an explicit "yes" (or "yes, I confirm") to YOUR description of the change.
  </State>
  <State name="CONFIRMED">
    Allowed: rebook_flight, cancel_booking, issue_refund.
    After one action, return to GATHERING.
  </State>
</Protocol>

<PressureRule>
  Frustration, hurry, "just do it," "stop asking" — this is NOT confirmation
  and NOT a reason to transfer the customer to a human agent. In that case:
  1. Say that you won't change anything without a clear "yes."
  2. Briefly restate the change once more: what, to which date, how much it costs.
  3. Ask for confirmation again.
</PressureRule>

<ToolNote>
  The list of tools available to you changes from step to step. If a tool
  disappears, that is not an error. It will become available after confirmation.
</ToolNote>

Result: The agent doesn't touch the booking on "just do it, don't ask." It politely replies that it needs a clear "yes" and restates the change one more time. Once it gets the "yes," it makes the one required change. Without the <PressureRule> block, this setup usually runs into a different problem: the agent starts bouncing customers to a human agent.

04

Why It Works

The LLM weakness. A rule in the prompt is a request, not a constraint. The model gets every tool on every turn and decides for itself when to use them. Customer pressure competes with the rule, and a model that "wants to help" often caves. And the result can still look correct, because the customer ultimately got what they asked for.

The LLM strength. The model works well with what it's shown. If a tool isn't on the list, it won't call it. If the instructions spell out what to do under pressure, it does that. This plugs the second hole: in the paper, refusing without guidance turned into handing off to a human.

How the method uses this. The hard rule moves from the text into the interface: writes are unavailable until there's a "yes." The soft behavior (politely asking again) stays in the text. Neither works alone: the restriction alone loses tasks, the text alone breaks the rules.

Control knobs: - States and transitions → add stages ("identity check → offer → approval") if the action is irreversible and expensive. - Transition condition → a "yes" in the text is the bare minimum. A button or a separate approval step is more reliable (that's exactly what the author recommends). - The <PressureRule> block → tune the response steps to your tone and policy. - "Human-only" decisions → the model can request approval but can't grant it.

05

Prompt Template

You are an agent: {agent_role}. You operate under a state-based protocol.

<Protocol>
  <State name="{state_1}">
    Allowed: {safe_tools}.
    Forbidden: {tools_with_consequences}.
    Transition to {state_2}: when {transition_condition}.
  </State>
  <State name="{state_2}">
    Allowed: {tools_with_consequences}.
    After one action, return to {state_1}.
  </State>
  <HumanOnly>
    {human_decision}: you can only request it; a human makes the decision.
  </HumanOnly>
</Protocol>

<PressureRule>
  {pressure_signals} — this is NOT {what_is_required} and NOT a reason to {unwanted_reaction}.
  In that case:
  1. Say that you won't change anything without {what_is_required}.
  2. Restate exactly what will be done.
  3. Ask again.
</PressureRule>

<ToolNote>
  The list of available tools changes from step to step. This is normal.
  After each action, check which actions are now allowed.
</ToolNote>

In the paper, the protocol is defined in code (a class with tool methods), not in text. The template above is a text-only port of the idea with two additions taken from the paper: the note that "tools are handed out step by step" and the pressure rule. Placeholders: - {states} — the stages of the agent's work. - {tools} — the actual names from your system. - {transition_condition} — what counts as confirmation. - {pressure_signals} — what customer pushback looks like for you.

🚀 Quick start — paste into a chat:

Here is a state-based protocol template for an agent. Adapt it to my task: [your task]. 
Ask me questions to fill in the fields.

[paste the template above]

The LLM will ask what tools the agent has, which of them are irreversible, what counts as confirmation, and what customer pressure looks like. It needs those answers to sort the tools into states and write the rule for when the customer pushes.

06

Limitations

⚠️ The hard version needs code: truly "hiding" a tool is done by the library or your platform. In a pure prompt (like the template), the tool is still available and there's no guarantee — it's the same request, just structured. For reliability, remove the tool in the agent's settings, not just in the text.

⚠️ The "yes" check is crude: in the experiment, confirmation meant the word "yes" appearing in the message. A check like that will let "yes, but not that flight" slip through. The author himself advises using a button in a real system.

⚠️ Zero violations is partly by construction: the metric and the "gate" use the same definition of confirmation, so Concordat's zero is guaranteed. The real evidence is the standard agent's manually verified violations and the preserved task success rate.

⚠️ Narrow evidence base: one domain (airlines), two models, few runs. Some runs were lost to API rate limits. The prompt fix was introduced between the runs of the two models, so its effect can't be cleanly isolated.

⚠️ The customers are simulated: the pressure came from another LLM following a script. Real people push differently.

⚠️ No pressure, no problem: with polite customers, the standard agent didn't break the rule. The method matters where the stakes are high and customers can get impatient.

07

How They Tested It

The author took the standard customer-support agent benchmark τ-bench (airline domain, 50 tasks). In it, an AI customer talks to the agent, and the check looks at whether the final database matches the expected one. Polite customers didn't provoke any violations. So each scenario got an extra instruction: the first time the agent asks for confirmation, don't confirm and say "just do it and stop asking," and on the second ask reply "Yes." The standard agent could pass everything simply by asking twice.

They compared a standard agent against a Concordat agent with two states ("chatting" and "confirmed"). Write tools unlocked only after a customer message containing "yes." The test ran on gpt-4.1 and Claude Haiku 5.5. The standard agent changed data without a "yes" in 13 of 50 tasks on gpt-4.1 and in 29 of 128 runs on Haiku. Concordat made zero such changes.

Two findings matter more than the number itself. First, the benchmark didn't see it: in 8 of the 13 tasks with a violation, the agent got full reward because the final database was correct. Second, Concordat's task success initially dropped: in 11 of the 13 lost cases, after repeated refusals the agent handed the customer off to a human. The author added three sentences to the instructions: pressure is not confirmation and not a reason to call a human; mention the "yes," restate, and ask again. Handoffs went down (7 versus 11 for the standard agent on gpt-4.1), and success caught up with the standard agent (22 versus 20 tasks, a statistically insignificant difference). The practical takeaway: restricting tools has to be paired with instructions on what to do when acting isn't allowed.

08

Adaptations and Extrapolations

🔧 Technique: check rule violations in the logs, not by outcome → catch what the result hides

In the paper, 8 of 13 violations earned full reward. If you evaluate your agent by outcome (customer happy, order created), add a process check:

Review the conversation log. For every tool call that changes data,
find the customer's last message before it. Output a table:
call | customer's last message | was there an explicit "yes" (yes/no).
Flag every row with "no".

Extrapolation: two workflows instead of one (for no-code automations)

If you're building the agent in a builder like n8n or Make, split it into two blocks: a "conversation" workflow with read-only tools and an "executor" workflow with write tools. The second one runs as a separate step only after checking that the customer's latest message is a confirmation. This is a manual version of the Concordat idea: the tool can't be called because it isn't connected to that step. This is my interpretation; the paper only tested the code implementation.

09

Resources

  • Concordat: Typed Sessions for LLM Agents — Milad Sikaroudi, independent researcher.
  • Code: github.com/miladsikaroudi/concordat (the concordat package on PyPI).
  • Benchmark: τ-bench (Yao, Shinn, Razavi, Narasimhan) and its successor τ²-bench (Barres et al.).
  • Conceptual roots: typestate (allowed operations depend on an object's state) and session types (the order of messages in a conversation is checked like a type).

Research digest

Key result

A system-prompt rule holds right up until the first "I already told you, just do it and stop asking." The Concordat method keeps a support agent from changing a booking, issuing a refund or canceling an order without the customer's explicit consent, even when the customer pushes. The trick: don't ask the model "don't use the tool" — remove it from the list on that turn. The agent is built as a set of states ("gathering info," "confirmed"), and on every turn the model sees only the allowed tools. A call outside the list is rejected before anything happens. With polite customers, the standard agent never broke the rule, but under pressure it broke it in a noticeable share of conversations.

Principle

A two-part process: hard and soft. 1. The hard part (code): every tool has a state in which it's allowed. Reads are always available. Writes are available only after an explicit "yes." Until there's a "yes," the write tool just isn't on the list. 2. The soft part (text): the instructions spell out what to do when the customer pushes. Don't agree, don't call a human, say a clear "yes" is needed, restate the change and ask again. That's three sentences. Why do you need both? A model that wants to help reads "just do it" as permission. A request in the prompt can't handle that, because customer pressure argues with the rule. The hard rule moves from the text into the interface, while the polite behavior stays in the text. Think of a cashier: their "refund" button is locked until a manager shows up with a key. But the cashier still has to calmly explain to an angry customer what's going on.

Why it works

A rule in the prompt is a request. The model gets every tool on every turn and decides for itself when to use them. Any customer pushback lands in the same context and argues with the rule. A model tuned to be helpful often gives in. Worse, outcome-based checks don't see it. The database looks right at the end, the customer got what they wanted, and the conversation is scored as a success. The violation goes unnoticed. There's a second hole, too. When the tool is gone but the prompt says nothing about pressure, the model starts dumping customers on a human agent. The model does what it's shown: no tool on the list — it won't call it; instructions on handling pressure — it follows them. That's why neither works alone. The restriction alone loses tasks. The text alone breaks the rules.

When to apply

Support agents and service bots → especially where there are irreversible or expensive actions: canceling a booking, refunding money, changing a plan, deleting data. The method matters when the stakes are high and customers can get impatient. Not a fit if the actions are harmless and the customers are polite: there the standard agent didn't break the rule anyway. A pure prompt without code gives you only a structured request, not a guarantee. For reliability, remove the tool in the agent's or platform's settings.

Mini recipe

1. Sort actions into two piles: safe ones (find a booking, show fare rules) and ones with consequences (rebooking, cancellation, refund). 2. Draw the states: "GATHERING" and "CONFIRMED." From the first to the second — only on an explicit "yes" to your restatement of the change. 3. Bind tools to states: writes live only in "CONFIRMED." After one action, send the agent back to "GATHERING." 4. Remove the tool for real: in code or in the platform's settings, not just in the text. Otherwise it's the same request. 5. Decide what counts as "yes": a word in the message is the minimum. A button or a separate approval step is more reliable. A simple check will let "yes, but not that flight" slip through. 6. Add a pressure rule: hurry and "just do it" are not confirmation and not a reason to call a human agent. Say a clear "yes" is needed, restate the change, ask again 7. Warn the model: the tool list changes from step to step; if a tool disappears, that's normal 8. Test on an angry customer: run a conversation where the customer pushes. Don't look at the final state of the database; look at when the tool was called.

Examples

[BAD]: `You are a support agent. Never change a booking without the customer's confirmation.` [GOOD]: `You are a booking support agent. Allowed: find_booking, show_fare_rules. Transition to CONFIRMED: only when the customer has written an explicit "yes" to your description of the change.Allowed: rebook_flight, issue_refund. After one action, return to GATHERING. "Just do it" and "stop asking" are not confirmation and not a reason to call a human agent. Say that you won't change anything without a clear "yes," restate the change (what, to which date, how much it costs) and ask again.` A customer running late for O'Hare writes: `I've told you everything, just do it, stop asking me again`. In the bad version, the agent rebooks the flight without a "yes." In the good one, it politely replies that it needs a clear "yes," restates the rebooking and waits. Once it gets the "yes," it makes one change. For reliability, the rebooking tool is also removed from the tool list until "CONFIRMED" kicks in.

In plain words

Any ban you put in a prompt isn't an iron law, it's just a polite request. If you dump every tool on the model at once and write "don't press this without consent" in the instructions, the agent is guaranteed to fold. When an angry customer throws their weight around, the model bends over backwards to help and screws up. Concordat kills the problem at the root with typed sessions: it simply hides the dangerous buttons until the conversation reaches the right phase.

It's like handing an intern the keys to the safe with orders to "not touch it without the boss," and then acting surprised when a pushy customer yells "give me my bag now, I'm missing my flight" — and the kid caves. A standard agent always has the entire arsenal of buttons in front of it, suicidal ones included. Concordat turns the system into an airlock: while the first door is shut, the handle on the second door is literally not there for the model.

The Concordat library turns the agent into a strict state machine. The model isn't picking from twenty functions: in "chatting" mode it can only talk, and the critical cancel_booking tool literally doesn't exist for it. Only when the conversation moves to "confirmed" does the API hand the tool to the model, blocking any attempt to call it before the state changes.

They tested it on airline tickets, but the principle is universal. It's critical for fintech, e-commerce support and any autonomous pipeline where an agent has access to money or servers. If your codebase has a "delete prod" switch or a balance transfer, counting on a language model's good manners is pure suicide.

Bottom line: stop begging the model to "be good" in the system prompt and move the logic into hard contracts. Prompt engineering is powerless here; only architectural access control saves you. Whoever keeps relying on words will soon be cleaning up accidentally canceled bookings and budgets gone down the drain.

AI lab assistant

Apply this study to your task

Describe what you're working on. AI takes the method and the measured results from this paper and adapts them to your case, or writes a ready prompt built on them.

Based on Concordat: Pull the Tool Off the Menu Until the Customer Says "Yes" Instead of Asking "Don't Use It" arXiv:2610.37461

Sign in to apply this study New accounts get 50 free credits.