Skip to content
AgentField
Governance

Permissions & Access Control

Tag-based ACL policies and permission enforcement for cross-agent authorization.

Tag-based permissions for agent access control

Control which agents can call which, who can read shared memory, and what external connectors are allowed to do.

In production multi-agent systems, not every agent should be able to call every other agent. The finance agent should not invoke the admin agent. External connectors should only access specific skills. AgentField provides tag-based access control policies that govern cross-agent calls, memory access, and connector permissions -- evaluated at the control plane before any execution begins.

from agentfield import Agent

app = Agent(
    node_id="trading-agent",
    tags=["team:finance", "env:production", "sensitivity:high"],
    local_verification=True,  # Evaluate policies locally
)

@app.reasoner()
async def execute_trade(trade: dict) -> dict:
    # Policy engine evaluates access BEFORE this handler runs —
    # callers without matching tags are denied at the control plane
    result = await app.call("order-executor.submit", input=trade)
    return result

@app.reasoner()
async def sensitive_operation(input: dict) -> dict:
    """Only agents with the right tags can invoke this reasoner."""
    return await app.ai(
        system="Process this sensitive financial data.",
        user=str(input),
    )
import { Agent } from "@agentfield/sdk";

const agent = new Agent({
  nodeId: "trading-agent",
  tags: ["team:finance", "env:production", "sensitivity:high"],
  localVerification: true,
});

agent.reasoner("executeTrade", async (ctx) => {
  // Policy engine evaluates access BEFORE this handler runs
  return await ctx.call("order-executor.submit", ctx.input);
});

agent.reasoner("sensitiveOperation", async (ctx) => {
  return await ctx.ai(JSON.stringify(ctx.input));
});
import (
    "context"
    "github.com/Agent-Field/agentfield/sdk/go/agent"
)

a, _ := agent.New(agent.Config{
    NodeID:            "trading-agent",
    Version:           "1.0.0",
    Tags:              []string{"team:finance", "env:production", "sensitivity:high"},
    LocalVerification: true,
})

a.RegisterReasoner("execute_trade", func(ctx context.Context, input map[string]any) (any, error) {
    // Policy engine evaluates access BEFORE this handler runs
    return a.Call(ctx, "order-executor.submit", input)
})

a.Serve(context.Background())
# Create a policy: finance team agents can call order executors
curl -X POST http://localhost:8080/api/v1/admin/policies \
  -H "Content-Type: application/json" \
  -d '{
    "name": "finance-can-trade",
    "caller_tags": ["team:finance"],
    "target_tags": ["team:finance"],
    "allow_functions": ["execute_trade", "submit"],
    "action": "allow",
    "priority": 100
  }'

What just happened

The examples showed the core enforcement model: tag-based policies evaluated at the control plane (or locally with local_verification) before a protected action runs. Authorization decisions live outside the agent process -- agents declare their tags, and the policy engine determines access.

{
  "target": "order-executor",
  "action": "call",
  "granted": false,
  "reason": "missing policy match"
}