Plugin trust
Almost everything a plugin declares is declarative: the board reads it and renders it,
inside a sandbox. Two tables are different in kind. [[hooks]] and [[tools]] name
Python that the board imports and calls in its own runner process
(Plugin contract). So they are gated by
an explicit, revocable trust decision rather than by loading the plugin.
Trusting a source
Section titled “Trusting a source”A bundle declaring [[hooks]] or [[tools]] does not load at all until its source is
trusted. Not “loads without its hooks”: the manifest a human approved is the whole
manifest. Its card under External plugins in Settings > Connections > Integrations
shows how much code it declares (hooks and tools), the bundle’s fingerprint and a Trust
code button; Revoke trust is always available and takes effect on the next refresh.
One trust record and one fingerprint cover both tables.
Trust is keyed on the bundle’s contents, not on its path or its pin. That single choice is what makes the rest true without any bookkeeping:
- moving a repo source’s pin changes the code, so the bundle is untrusted again on the next read: “update the plugin” can never quietly mean “run new code under the old approval”;
- editing a trusted local folder’s
hooks.pyasks again too, which a pin-keyed record could never notice, since a folder has no pin; - re-pinning back to a commit that was already trusted simply works again, because the approved bytes are back.
A bundle containing a symlink cannot be trusted at all: its importable surface points somewhere the fingerprint does not describe.
An agent can request trust for a plugin it built, through the same set_plugin_source
tool and the same per-argument approval, by passing trust_hooks
(Load a plugin).
Publishing a bundle and letting it run code are two different approvals, so one never
stands in for the other, and a repo must be fetched first: the board cannot show you code
it has not seen.
What trust actually costs
Section titled “What trust actually costs”Stated plainly, because the alternative is discovering it:
- A trusted hook is equivalent to full board access. It runs in the runner process, as the board’s user, with the board’s credentials and API reachable, and importing it runs its module body. There is no sandbox here. Read the code you trust.
- Trust persists until the bundle’s code changes or you revoke it. An agent’s permission grant is spent by its run; the trust it wrote is not.
- Trust is board-global, because the plugin source list is: a hook trusted once runs on every ticket on every board.
- On a board with no auth token configured, the browser-only rules that protect all of this are no-ops, exactly as they already are for the plugin path lists: there is no human and agent distinction to enforce on an open loopback board.
Editing a hook on a running board does not hot-reload it; restart the runner, the same as for any other runner code change.
Two trust levels, one bridge
Section titled “Two trust levels, one bridge”Registering one of the board’s own contributions (a system prompt append, an SDK hook
matcher) is still Python in the board’s source, and deliberately so. A plugin reaches the
same chain only through [[hooks]], and only from a source a human has trusted. Those
remain two different trust levels; what trust adds is an explicit, revocable bridge
between them rather than none.