Permission

Coming soon

permission_mode gates every tool call the model makes. Set it on the Agent:

from mistralai.agents import agents

agent = agents.Agent(
    model="mistral-medium-3-5",
    instructions="Use the tools.",
    permission_mode="deny",
    harness=agents.Harness(tools=[deploy_service]),
)
ModeWhat happens on a tool call
"auto" (default)The call runs. There is no gate.
"deny"The call is refused. The model receives permission denied: <tool>
"ask"The session opens an approval callback. The turn waits for your answer.

The gate is unscoped. It applies to every tool call: your own tools and the sandbox built-ins such as bash and run_typescript. There are no per-tool rules.

Answer an "ask"

Answer an "ask"

"ask" needs a session. The turn stops at an ApprovalCallback and continues when you answer it:

from mistralai.vibe.harness.app_server import session as harness_session

from mistralai.agents import agents

agent = agents.Agent(
    model="mistral-medium-3-5",
    instructions="Use the tools.",
    permission_mode="ask",
    harness=agents.Harness(tools=[deploy_service]),
)

async with await agent.create_session() as session:
    prompt = [harness_session.TextContentBlock(text="Deploy the service.")]
    async for event in session.run_turn(prompt):
        if isinstance(event.payload, harness_session.CallbackOpenedEvent):
            await session.answer_callback(
                harness_session.CallbackResult(callback_id=event.payload.callback.id, output=True)
            )

The callback carries title, tool_call_id and the tool input, so you can show the user what the agent asks for.

output=True allows the call. {"allow": True} and {"decision": "allow"} do the same. Every other value refuses it.

:::caution agent.run() cannot answer a callback agent.run() has no callback channel. With permission_mode="ask" the turn stops at the approval and does not terminate. Use create_session(). :::

create_session(permission_mode=...) sets the mode for one session. A deployment-backed session refuses the argument: it uses the mode pinned in its deployed Agent.

:::note A refusal is absent from the history "deny", and an "ask" that you refuse, both compile to a pre_tool_call Hook skip. A skip writes no tool_call entry and no tool_result entry, so list_history() does not show that a call was refused. Record the refusal yourself if you need the trail. :::

See also

See also

  • Custom hooks - permission is a pre_tool_call Hook. Write your own for a rule the SDK does not ship.
  • Tools - what the gate applies to.
  • Sessions - the callback channel that "ask" needs.