Tool Policy
Govern what an agent may do with the tools it holds — by behaviour rather than by name, with a real gate instead of a sentence in a prompt.
Ticking a tool on an agent decides whether it has the tool. Tool policy decides what it may do with it.
The two are different questions, and only having the first one caused real problems. run_sql_query is one door for SELECT and for DROP, so a name-based allowlist admits or refuses both together. The old workaround was to ask in the system prompt — "confirm with the user before any write query" — which is a sentence, not a gate. A model can decline to follow it, and a model told to call again with confirm=true can simply do that.
Behaviour, not names
Tools declare what they do, and a policy speaks about those declarations. It has three rows, riskiest first:
| On the screen | Category | Means |
|---|---|---|
| Tools that change data permanently | destructive | The tool declares that it modifies data in a way that cannot be undone |
| Tools that reach outside this workspace | open_world | The tool declares that it talks to systems this workspace does not control |
| Tools that don't say what they do | undeclared | Most tools: nothing declared, an outside server's "read-only" claim, or a tool that changes something without reaching outside |
Which row a tool lands in follows from what it says it does. A custom tool says it in three answers (What it does: Reads only, Changes something or Deletes something; Safe to repeat; Reaches outside this workspace):
- A rule for one tool (below) decides first.
- Deletes something → change data permanently.
- Reaches outside this workspace, whatever else it does, reads included → reach outside. Every HTTP tool reaches outside until you untick it.
- Reads only and stays inside, from a tool you made or one of SynapseOrch's own → it runs, with no row to pass.
- Changes something and stays inside, or answers Not set → don't say what they do.
The categories are ordered riskiest first, and the first one a tool matches decides. Each maps to one of three outcomes:
| Decision | On the screen | What happens |
|---|---|---|
allow | Allow | The call runs |
confirm | Ask first | The run pauses and waits for a person |
deny | Block | The call is refused and the agent is told so |
For one tool
Under For one tool, Add a rule for one tool… picks a tool by name and gives it its own Allow, Ask first or Block, whatever its row says. It is stored beside the categories as tool:<name>, and it wins over the tool's category.
A tool's answers come from different places, and are trusted differently:
- Your own custom tools say what they do in the tool editor; see Custom tools. Imported from a file, a tool's answers are a claim until someone saves it.
- Synapse AI may mark a tool it makes as riskier than its method suggests (a
GETthat cancels an order), never safer. - An outside MCP server's answers are a claim (below).
Where a policy comes from
Three layers, each overriding the last:
- Built-in defaults —
allowfor every category. - The deployment — the
tool_policy_defaultssetting, workspace-wide. - The agent — its own
tool_policy, set in the agent editor.
A category nobody mentions inherits from the layer above it.
The default is allow, on purpose
No existing agent changes behaviour when you upgrade. A closed default would
have silently broken every agent already running — the same reasoning as the
empty database allowlist. Opt in deliberately, starting with destructive.
A good first policy is destructive: confirm workspace-wide, then relaxing it per agent for the ones whose whole job is to write.
What confirm does
In chat, the turn stops and the pending call is parked together with the loop's last turn-boundary snapshot. You approve or reject it in the conversation, and the turn resumes from that snapshot. This is the one pause a chat turn cannot come back from on its own, which is why the call and the snapshot are stored together.
In a workflow, the run raises the same request and checkpoints, exactly as a human gate does, so an unattended run does not die holding a half-finished turn — it waits, and resumes when somebody answers.
In a Tool step, the step's one call is checked the same way — against the workspace's policy, or the agent's when the step's JSON names one. A blocked tool fails the step before any model call; one that asks pauses the run, and approving runs that exact call, once. See the Tool step.
For a helper (spawn_subtask), a tool the agent's policy blocks or would ask about is simply not handed over, and the agent is told which, so it can make the call itself — where it will be asked. A member of a Team agent asks under its own policy, and approving its call runs it as that member.
Where nobody can answer, asking is not possible, so it becomes refusing: a chat widget visitor's turn treats confirm as deny.
Saving to memory asks too, outside these categories: once a turn has read a tool's result, a file or an image, its remember waits for a person. See Memory.
MCP servers are trusted asymmetrically
A tool hint from an external MCP server is a claim, not a boundary — the MCP specification says so plainly. SynapseOrch treats it that way:
- A third-party server saying "I am destructive" is believed.
- A third-party server saying "I am safe" is not believed — a read-only claim is treated as
undeclared. - SynapseOrch's own servers are declared in the repository and are believed either way.
So the undeclared category is where most third-party tools land, and setting it to confirm is the strongest single lever you have over a server you do not control.
Setting it
Per workspace — Settings → the tool_policy_defaults entry.
Per agent — the Tool policy section of the agent editor, which overrides the workspace for that agent only.
An agent saved through the API keeps whatever policy it had; the field is explicit on the agent model precisely so a round trip does not quietly drop it.
Vault Tools for Agents
The vault is a persistent, shared file system accessible to agents across sessions. Think of it as the agent's long-term working directory — a place to save results, build up knowledge bases, and share files between agents and runs.
Variables
One place for the values that appear in fifty tools and prompts — base URLs, account ids, tone of voice — referenced as {{ global.key }}.