@@ -254,10 +254,48 @@ shape.
254254
255255- ` kind: "tool" ` plugins export ` createToolPlugin(credentials) ` and contribute
256256 posix ` ToolPlugin ` s, resolved in ` src/plugins/tool-plugins.ts ` and wired into
257- the toolset in ` src/tui/runner.ts ` and ` tools.ts ` (appended last, so they cannot
258- shadow core middleware).
259- - A tool plugin is wired in only when ** enabled AND consented** . Enabling one in
260- ` /plugins ` prompts a one-time y/n consent recorded in ` settings.plugins[id] ` .
257+ the toolset by the shared session runners and ` src/agent/tools.ts ` .
258+ - The installed-plugin contract is the exported ` ToolPlugin ` type from
259+ ` @intx/tools-posix ` . In addition to ` tools ` , ` middleware ` , and ` dispose ` , it
260+ may provide ` authorize?: AuthorizeFn ` (the ` AuthorizeFn ` type is exported by
261+ ` @intx/agent ` ). Corbits calls it before a tool invocation as
262+ ` authorize(resource, action, context) ` , with ` resource ` set to
263+ ` tool:<canonical-name> ` , ` action ` set to ` "invoke" ` , and ` context ` set to the
264+ canonical ` ToolCall ` . Aliases and their arguments are normalized first (for
265+ example, ` bash ` is presented as ` run_shell ` ). The callback returns the
266+ exported ` AuthzCallResult ` shape: an ` effect ` of ` "allow" ` , ` "ask" ` ,
267+ ` "deny" ` , or ` null ` , plus ` matchingGrants ` and ` resolvedBy ` ; a deny may also
268+ include a non-empty ` reason ` .
269+ - A tool plugin participates only after its module is trusted and loaded and
270+ when it is ** enabled AND consented** . Enabling one in ` /plugins ` prompts a
271+ one-time y/n consent recorded in ` settings.plugins[id] ` ; manifest
272+ ` defaultEnabled ` does not activate tool plugins by itself. Disabled,
273+ unconsented, and metadata-only untrusted plugins contribute neither
274+ middleware nor authorization.
275+ - Authorization composes conservatively. Across authorizing plugins, deny (and
276+ the fail-closed ` null ` effect) blocks, ask is stronger than allow, and the
277+ first result at the strongest effect is retained. Corbits then combines that
278+ result with its own ` PermissionGate ` monotonically: a plugin deny blocks; a
279+ plugin ask can strengthen a Corbits allow into an approval request; and a
280+ plugin allow cannot override a Corbits deny or ask, standing-grant rules, or
281+ any other Corbits guard. Corbits hard denials short-circuit before plugin
282+ authorization runs.
283+ - ` null ` , a malformed result, or a thrown/rejected callback fails closed as a
284+ deny. Exception and validation details are logged only through scrubbed
285+ diagnostics and are not exposed as the public denial reason. By contrast, a
286+ plugin's explicit non-empty ` reason ` on an ` effect: "deny" ` result is used as
287+ the public block reason; omit it for the generic denial.
288+ - A plugin ` ask ` uses the existing approval flow. Because plugin asks provide
289+ no grant scopes, they are ** Allow Once** only and cannot create or persist a
290+ standing grant. If no interactive approval path is available, the ask is
291+ denied. Existing Corbits asks keep their own scopes and persistence behavior.
292+ - ` authorize ` is independent of ` middleware ` : an allowed invocation still runs
293+ the existing middleware chain, and tool-result secret scrubbing and
294+ truncation remain outermost after installed middleware returns. Installed
295+ middleware is still appended after core middleware, so it cannot bypass
296+ post-tool redaction. If no active tool plugin provides ` authorize ` , Corbits
297+ does not install a plugin-authorizer wrapper on the permission hot path; the
298+ pre-existing gate and middleware behavior is unchanged.
261299- Per-kind verify in ` /plugins ` covers web (trial search) and tool (load check).
262300- ` plugins/example-tool ` is a worked example of a ` tool ` plugin.
263301
0 commit comments