Appearance
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:
| Context | allowedTargets | allowedOps | approvalRequiredFor |
|---|---|---|---|
actor-readonly | — | $introspect, session_state.read | — |
actor-edit | — | — | matrix_invoke |
repo-coding | system.agents, system.registry, system.tools.mcpBridge | — | package_validate |
test-runner | system.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 atargetMount; a tool call whosetargetis outside that subtree fails withTOOL_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/maxToolCalls—AgentActor.ts:197-200). When a deny match wins, the call fails withTOOL_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 resultApproval 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
BudgetValplumbing 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.