Architecture
Permission System
Group-level isolation, sandbox execution, mount allowlists, and container mode.
goClaw's permission system lets you control exactly what each agent sees, touches, and does. It's built on two concepts: groups (logical isolation) and sandbox (technical enforcement).
Groups
A group is a named configuration set that scopes an agent context. Every agent execution runs within a group. Groups control:
- Which knowledge files the agent can read
- Which MCP tools the agent can call
- Which CRM contacts the agent can see (filtered by group tag)
- The technical sandbox level (process vs. container)
Group configuration
Groups are defined in config/permissions.yaml:
groups:
outbound_sales:
description: "SDR agent — outbound prospecting"
knowledge_mounts:
- ./knowledge/public # Company-wide knowledge
- ./knowledge/products # Product knowledge
- ./knowledge/objections # Objection handling
tool_allowlist:
- crm_search
- crm_get_contact
- crm_create_contact
- crm_add_note
- crm_schedule_followup
- knowledge_search
- knowledge_file_curiosity
- web_search
- send_email
- send_sms
sandbox:
filesystem: read_only
network: allow
container: false
customer_support:
description: "Support agent — inbound only"
knowledge_mounts:
- ./knowledge/public
- ./knowledge/products
- ./knowledge/support # Support-specific guides
tool_allowlist:
- crm_search
- crm_get_contact
- crm_update_contact
- crm_add_note
- knowledge_search
- knowledge_file_curiosity
- send_email
- send_telegram
sandbox:
filesystem: read_only
network: allow
container: false
admin:
description: "Human admin access — full permissions"
knowledge_mounts:
- ./knowledge # All knowledge
tool_allowlist: "*" # All tools
sandbox:
filesystem: read_write
network: allow
container: false
Group assignment
Messages are assigned to groups based on channel routing rules:
routing:
email:
domain_rules:
- pattern: "*@yourcompany.com"
group: admin
- pattern: "*"
group: outbound_sales
telegram:
group: customer_support
sms:
group: outbound_sales
You can also assign a group directly when triggering agent execution via the API or admin dashboard.
Knowledge mounts
Knowledge mounts are directory paths the agent is allowed to read. Paths outside the mount list are inaccessible — the knowledge_search and knowledge_get tools enforce this at query time.
knowledge_mounts:
- ./knowledge/public # Readable
- ./knowledge/products # Readable
# ./knowledge/internal # Not listed → inaccessible
Relative paths are resolved from the project root. Absolute paths are supported.
Tool allowlist
The tool_allowlist is an array of MCP tool names the agent can call. Any call to a tool not in the allowlist is rejected with an error logged to the audit trail.
tool_allowlist:
- crm_search
- crm_get_contact
- send_email
Use "*" to allow all tools (human admin only — not recommended for agent groups).
CRM scoping
Contacts are tagged with their originating group. The CRM tools automatically filter results to the current group context:
// Agent in "outbound_sales" group
await mcp.tool("crm_search", { query: "acme" });
// → Returns only contacts with group_id: "outbound_sales"
This means your outbound sales agent and customer support agent see different contact sets, even though they share the same CRM database. Contacts can be transferred between groups via the admin dashboard.
Sandbox modes
Process isolation (default)
Each agent execution runs in a Node.js worker thread with:
- Read-only access to allowed knowledge paths (enforced by knowledge module)
- Tool allowlist enforcement (enforced by MCP router)
- No direct database access (all CRM operations go through MCP tools)
- Shared process memory (not fully isolated from the main process)
This mode is appropriate for trusted agent configurations with minimal risk.
Container isolation
When sandbox.container: true is set, agent execution moves into a Docker container:
groups:
untrusted_agent:
sandbox:
filesystem: read_only
network:
allow:
- "api.anthropic.com"
- "api.openai.com"
- "api.resend.com"
deny: "*"
container: true
container_config:
image: "goclaw/agent-sandbox:latest"
memory_limit: "512m"
cpu_limit: 1.0
user: "1000:1000" # Non-root
Container mode enforces:
- Strict filesystem isolation — only mounted knowledge directories visible
- Network allowlist via iptables rules in the container
- Non-root execution (UID 1000)
- Memory and CPU limits
- No access to host credentials (only required tokens passed via environment at launch time)
Container mode is recommended for:
- Multi-tenant deployments where different tenants run different agents
- Agents with access to sensitive external APIs
- Deployments where agent code changes frequently
Audit logging
All agent actions are logged to the audit trail regardless of group:
interface AuditEntry {
id: string;
timestamp: number;
group_id: string;
agent_id: string;
action: string; // "tool_call" | "message_sent" | "contact_created" | etc.
tool_name: string | null;
tool_input: unknown;
tool_result: unknown;
contact_id: string | null;
duration_ms: number;
success: boolean;
error: string | null;
}
The admin dashboard shows the audit log per group with filtering by tool, contact, and time range. Audit entries are retained for 90 days.
