Skip to content

Tool permissions

Two layers of permissioning are wired today: the declared permissions field on a ToolContextSpec, and the runtime ISecurityDelegate consulted on every tool call.

Declared permissions

From ToolContextSpec.permissions (tools/ToolContextSpec.ts:9-15):

ts
permissions: {
  allowedTargets?: readonly string[];   // explicit mounts callable
  allowedOps?: readonly string[];        // explicit ops callable (cross-cutting)
  allowedFactDomains?: readonly string[];
  approvalRequiredFor?: readonly string[];
  deny?: readonly string[];              // overrides allowlists
}

Examples from the built-in contexts:

ContextallowedTargetsallowedOpsapprovalRequiredFor
actor-readonly$introspect, session_state.read
actor-editmatrix_invoke
repo-codingsystem.agents, system.registry, system.tools.mcpBridgepackage_validate
test-runnersystem.agents$traceQuery

deny is currently unused but reserved as the always-overrides-allow list.

Runtime enforcement: ISecurityDelegate

oracle/interfaces.ts:42-48:

ts
interface ISecurityDelegate {
  isInSubtree(target: string): boolean;
  isCommandAllowed(op: string): boolean;
}

AgentActor implements both:

  • isInSubtree(target). Restricts tool calls to the agent's authorized scope. The agent is anchored to a targetMount; a tool call whose target is outside that subtree fails with TOOL_SCOPE_VIOLATION (AgentActor.MX_AGENT_ERRORS). The check is structural — it looks at mount prefix matching.
  • isCommandAllowed(op). Cross-checks the call against the active execution policy (ExecutionPolicy.allowCommands / denyCommands / maxToolCallsAgentActor.ts:197-200). When a deny match wins, the call fails with TOOL_INVOKE_FAILED.

Both checks run before the tool is dispatched. If either rejects, the LLM gets a structured error message in the tool result and the loop continues — the model is given the chance to choose a different action.

Approval flow

When a tool is in approvalRequiredFor, the oracle emits an approval.required activity frame instead of dispatching. The flow:

oracle:  emits approval.required(toolCall=…)
caller:  shows UI to human user
caller:  invokes session.respond { approved: true|false }
oracle:  sees response, either dispatches the call or returns 'denied' as the tool result

Approval is a session-level affair — session.respond in the (separate) coding-agent packages uses the same pattern. The agent platform exposes the activity frame; the rendering and acknowledgement happen in Director / Chat / Smithers UI.

What is NOT enforced today

  • Per-principal quotas. The BudgetVal plumbing exists in omega-lisp's governance layer but is not wired into the agent platform.
  • Cross-tenant deny rules. Authority root is a hard boundary at the bus level; the agent platform does not need to re-enforce it.
  • Tool-result content filtering. Tool results are passed back to the model verbatim. Output sanitization is the tool's responsibility.

See also

Source: projects/matrix-3/packages/agents/src/oracle/interfaces.ts:42-48, projects/matrix-3/packages/agents/src/AgentActor.ts:101-200, projects/matrix-3/packages/agents/src/tools/ToolContextSpec.ts:9-15.