Warden Agent Development Mode
Unrestricted tool access — give the assistant every tool a Core announces, at every tier. Development only. What it costs, and how to turn it off.
What this is
The Warden Agent normally sees a deliberately narrow slice of what your Core can do. Unrestricted tool access removes that slice and gives it every tool the bound Core announced, at every tier — reads, mutations and destructive operations alike.
It exists for one situation: a development platform with no users, where you want to find out what the assistant is actually good for before deciding what it should be allowed to do. Start from the whole surface, watch what happens, then add policy from what you learned.
This is a development-only mode. Do not run it on a deployment that has users, customer data, or clusters you cannot afford to lose. It is off by default and nothing in the product turns it on for you.
Where the switch lives
Both Warden Agent switches are rows in the Hub database, not environment variables:
| Switch | Stored at | What it does |
|---|---|---|
| Warden Agent | system_settings scope warden, key agent_enabled | Whether the agent exists at all on this deployment |
| Unrestricted tool access | system_settings scope warden, key unrestricted_tools | Whether the tool-tier gate is suspended |
They used to be WARDEN_AGENT_ENABLED and WARDEN_AGENT_UNRESTRICTED_TOOLS in
the Hub's environment, which meant a change required shell access to every Hub
node plus a container restart — and the production deploy pipeline, which
publishes a DNS deploy signal and carries no environment, could not set them at
all.
They are deployment-wide, not per organization: one Hub, one answer, every
org. They are not part of Settings › Admin › Warden Agent's per-org
configuration even though they are shown on the same page.
Turning it on
In Settings › Admin › Warden Agent › Deployment switches, as a platform
admin (Keycloak realm role admin or superadmin). An organization admin
cannot do this — the org-admin role governs one org, and this switch governs
every org on the Hub.
Turning unrestricted access on is a two-step control: type unrestricted to
arm the button, then press it. Turning it off is a single click.
There is no restart. The change is visible on every Hub replica within a few seconds. Unrestricted access requires the Warden Agent switch to be on as well — it widens the agent's reach, it does not create the agent.
Every flip of either switch, in either direction, writes an admin_audit_log
row with your identity and the old and new value.
The stored value is matched exactly
The stored value must be the exact string true. Everything else is off,
and the discipline moved with the switch — it now guards the database value
rather than the environment one:
| Stored value | Result |
|---|---|
| no row | Off |
"" (empty) | Off |
false | Off |
TRUE, True | Off — no case folding |
1, yes, on | Off — no truthiness |
" true " (padded) | Off — no trimming |
true | On |
The strictness is deliberate. Every one of those near-misses is a plausible way to switch this on by accident, and none of them do. The API refuses anything but a JSON boolean, so the UI cannot store one of them either.
The environment can still force it off
WARDEN_AGENT_UNRESTRICTED_TOOLS and WARDEN_AGENT_ENABLED survive as a
one-way OFF override:
| Environment variable | Database value | Effective |
|---|---|---|
exactly false | anything | Off |
| unset, or any other value | exactly true | On |
| unset, or any other value | anything else | Off |
Read the table twice, because the asymmetry is the point: the environment can
only force the flag off. It can no longer turn it on. A leftover
WARDEN_AGENT_UNRESTRICTED_TOOLS=true on a node does nothing at all.
The brake is PER-NODE. Set it on every node.
This is the one thing on this page you can get wrong in a way that hurts you.
The switch is a database row: one value for the whole deployment. The
environment brake is not — it is the environment of one container, and a
Hub node cannot see any other node's environment. Set
WARDEN_AGENT_UNRESTRICTED_TOOLS=false on two of three nodes and you have
gated two of three nodes. The third obeys the stored switch, and requests reach
it as normal.
That failure is invisible from the wrong angle. With the switch stored on and the brake set unevenly:
- A request routed to a braked node reports the mode as held off — for that node.
- A chat turn routed to any other node is handed every tool the bound Core announced, at every tier.
So the settings page never claims the deployment is gated. It reports the
answer given by the node that served your request, and every field it reads
is named for that (effective_on_this_node,
env_forced_off_on_this_node) — as are the corresponding fields in the
admin_audit_log payload. When the switch is stored on and your node is
braked, the status chip reads Active · off on this node, not Gated.
To gate a deployment with the environment brake, set the variable on every node and restart each one. If you cannot guarantee that, switch the stored value off instead: that is the one control that is genuinely deployment-wide.
Why keep it: while the switch lived in the environment, turning unrestricted
mode on required shell access to the nodes, and that inaccessibility was itself
a control. Moving it into a database row hands the switch to everyone who can
write that row. Setting WARDEN_AGENT_UNRESTRICTED_TOOLS=false in a node's
environment bolts the door from outside the application — no UI, API or SQL
statement can unbolt it. That is the brake to reach for on any Hub that must
not be able to enter this mode, whatever a future admin clicks.
When the override is in force on the node serving the page, the settings page says so, and says whether the stored switch is currently being overridden there. A flip that changes nothing on that node is never silent.
How you know it is on
You cannot miss it, by design:
- The moment it turns on, the Hub prints a banner naming the switch and what it did — on the transition, not only at startup, because the value can now change while the Hub is running. Turning it back off prints a line too.
- On every turn, the request log carries
[warden][UNRESTRICTED]lines showing how many tools were offered and which tool is being dispatched, with its real tier. - In the agent drawer, the mode chip reads
Unrestrictedinstead ofRead-only, and a red banner sits above the transcript for the whole session. - In
Settings › Admin › Warden Agent, a red notice states that the mode is active, and the Deployment switches card shows the switch asActive— orActive · off on this nodewhen the stored switch is on but the node that answered carries the environment brake.
If you are ever unsure which mode a Hub is in, open the drawer. The answer is on screen.
Turning it off
Press Restore the tier gate in Settings › Admin › Warden Agent › Deployment switches. One click, no restart, effective on every replica within
seconds.
If you cannot reach the UI — or you want it held off regardless of what anyone
stores — set WARDEN_AGENT_UNRESTRICTED_TOOLS=false in the Hub node's
environment and restart that node. That override cannot be lifted from inside
the application. It gates only the node whose environment carries it, so
set it on every node; see the brake is
per-node above. Pressing
Restore the tier gate remains the only single action that gates the whole
deployment.
That is the entire procedure. Nothing was deleted to build this mode. The
tier and may_be_read gate is intact in the code and starts enforcing again on
the next request. There is no migration to reverse, no allowlist to prune, and
no code to restore.
The database was never touched either: mcp_tool_metadata.may_be_read remains
FALSE for every tool, exactly as it was. This is a runtime bypass, so your
stored tier data keeps meaning what it says, and the G-7 state check keeps
telling you the truth about it.
What it actually costs
This section is not a warning label. It is the thing you are choosing, stated plainly so it stays legible three weeks from now.
Untrusted text and dangerous tools share one context window. The assistant reads text it did not write — workload labels, container names, log lines, annotations, the descriptions of the Core's own tools. Any of that can be authored by whoever deployed the workload. In normal operation that text sits alongside read-only tools, and the worst case is a misleading answer. In this mode it sits alongside tools that can read your secrets and delete your clusters.
The assistant is instructed to treat tool output as data, to confirm destructive actions with you first, and never to retry a mutating call that errored. Those are mitigations, not boundaries. In this mode the model's judgement is the only thing between a hostile string in a pod label and a destructive call, because the gate that used to be the boundary is switched off.
That includes confirm-to-mutate. Elsewhere in the product it is described as always on and not disableable; in this mode there is no server-side confirmation step for it to enforce, so it is a prompt instruction and nothing more. Read it as "the model has been told to ask first", not "the platform will stop an unconfirmed write".
Specifically, with the flag on:
- Tools with no tier classification at all are offered. The Hub has tier rows for roughly 71 tools; a current Core announces around 192. Normally the ~121 unclassified ones fail closed. Here they are included.
- Credential-disclosing tools (
get_secret,list_stack_secrets, and friends) are reachable, and their output lands in the chat transcript. - The relay's read-verb allowlist and its independent tier re-read are both skipped.
What stays on
The flag suspends tier policy. It does not turn the Hub into an open door:
- Tenancy. The bound instance must still belong to the caller's organization, re-checked at dispatch time on every call.
- Who can switch it. Platform admin only, and every flip is in the admin audit log. Org admins cannot reach it.
- Attribution. Every call is still tied to the human who asked for it.
- Rate limits and the monthly token budget. Probing should not be able to bill without limit.
- Abort on disconnect. Closing the drawer stops the agent from starting further work and cancels the Hub's wait on a call already in flight. It does not cancel work the Core has already begun — a destructive operation that reached the cluster will finish. Verify state afterwards rather than assuming the close undid it.
- Tool-name well-formedness. Malformed names are refused.
- Description sanitisation. Tool descriptions are still stripped of control characters and length-capped. You opted into unrestricted tool access, not an unbounded prompt-injection channel.
Tool list limits
The unrestricted list is capped at 256 tools, which clears a current Core's ~192 with room to spare. If a Core ever announces more, the extra tools are dropped — and you are told, in the log line, in the drawer banner, and in the assistant's own instructions.
Tools whose names are not lower_snake_case are also dropped, and counted in
the log line. The relay refuses such names in both modes, so offering them
would produce tools the assistant can see and call but never successfully
dispatch. A silent cap would let the UI claim
"unrestricted" while the model held two thirds of the surface, which is exactly
the kind of quiet wrongness this mode is meant to expose rather than create.
Choosing the assistant's model
The model is configured in Settings › Admin › LLM Providers › Model per Job Type, in the AI Assistant row, alongside every other model in the
product. Options are Opus 5, Sonnet 5 (default) and Haiku 4.5. The setting is
per-organization and applies from the next message.
The Warden Agent settings tab shows which model is in use but no longer sets it — there is one place to change it.