/stop, /new, or /compress even under a privileged identity.
Quick Start
1
Interactive human turn β command runs
A real user typing into a live chat keeps the default (
allow_control=True), so a slash-prefixed message is classified as a command.2
Untrusted producer β command is neutralised
A webhook, relay, or wake producer marks its message
allow_control=False, so the same text is handled as plain text instead of a privileged command.How It Works
A producer setsallow_control=False on non-interactive content; is_command short-circuits to False before the gateway ever classifies the message, so it is dispatched as plain text.
The Two-Gate Model
Command classification passes through two independent gates β content-trust fires first, identity ACL second. Identity alone is not enough: untrusted content is often attributed to an allowed identity β a webhook bound to the owner, a relayed or proactive event on the botβs own session. Identity ACL passes, but content-trust does not, so the command never executes.What This Prevents
Content provenance is now a first-class part of the contract, so a/-prefix in an untrusted body no longer drives privileged session control.
For Adapter Authors
Set allow_control=False on non-interactive producers
Set allow_control=False on non-interactive producers
When you write an adapter or a webhook/relay/proactive producer, set
allow_control=False on the BotMessage unless the content is a real, interactive human turn on that channel. The default (True) keeps todayβs behaviour for interactive turns; the primitive is safe by narrowing it for untrusted sources.Round-trip carries the field
Round-trip carries the field
to_dict() and from_dict() carry allow_control. from_dict defaults it to True when the key is absent, so older serialised payloads still deserialize as trusted.Layer identity ACL on top
Layer identity ACL on top
Content-trust is the first gate.
CommandAccessPolicy.can_run(user_id, cmd) still runs afterward for messages that pass content-trust, so identity gating (admin_users, user_allowed_commands) is unchanged.Configuration Reference
Backward Compatibility
The default isTrue, so todayβs interactive traffic is unchanged. from_dict defaults the field to True when absent, so pre-PR serialised messages still deserialize as trusted. There is no config flag, CLI flag, or YAML change β this is a contract primitive, not a user-facing feature knob.
Related
Untrusted Request Fencing
Prompt-plane counterpart β wraps untrusted payload content as data
Bot Command Access Control
Identity-based ACL that layers on top of content-trust
Webhook Channel
The primary untrusted producer
Gateway Inbound Hooks
HTTP-triggered agent runs with the same trust posture
Bot Chat Commands
What the gated commands actually do
Inbound Message Gate
Admission after is_command classifies

