Permission Modes in Craft Agents: Safe, Ask, and Allow-All Explained

Craft Agents provide three permission modes—Safe (Explore), Ask (Ask to Edit), and Allow-All (Execute)—that enforce granular control over tool execution through the PermissionManager class in packages/shared/src/agent/core/permission-manager.ts.

The craft-ai-agents/craft-agents-oss repository implements a robust permission system that governs how AI agents interact with bash commands, file systems, and APIs. Understanding these permission modes is essential for deploying agents securely across exploratory, interactive, and automated workflows.

The Three Permission Modes: Safe, Ask, and Allow-All

Craft Agents map internal keys to user-facing canonical names in packages/shared/src/agent/mode-types.ts. Each mode determines whether the agent can write to the filesystem, execute arbitrary commands, or access external APIs without supervision.

Safe Mode (Explore)

Safe mode operates as a read-only sandbox where all write-type tools are blocked. When running in safe (internally keyed as 'safe', displayed as Explore), the agent cannot modify files, execute destructive bash commands, or push to git repositories. The system evaluates tool calls against a whitelist defined in the permissions JSON, rejecting any operation that could alter system state.

Ask Mode (Ask to Edit)

Ask mode enables full tool functionality while requiring user confirmation for high-risk operations. Internally keyed as 'ask' and displayed as Ask to Edit, this mode allows the agent to propose dangerous actions—such as rm, sudo, or git push—but surfaces these requests to the user for explicit approval before execution. The PermissionManager identifies dangerous commands using a hard-coded DANGEROUS_COMMANDS set in permission-manager.ts.

Allow-All Mode (Execute)

Allow-all mode grants unrestricted autonomous execution for fully automated workflows. Internally keyed as 'allow-all' and displayed as Execute, this mode bypasses all permission checks and dangerous-command detection. When allow-all is active, shouldAllowToolInMode returns allowed: true immediately, enabling the agent to run without prompts or whitelisting constraints.

How Permission Enforcement Works in Craft Agents

Permission enforcement follows a centralized evaluation pipeline that checks the current session mode before allowing tool execution.

Mode Evaluation and Policy Logic

The enforcement entry point is PermissionManager.evaluateToolCall(toolName, toolInput) in packages/shared/src/agent/core/permission-manager.ts. This method retrieves the active mode via getPermissionMode(sessionId) and delegates the policy decision to shouldAllowToolInMode(toolName, toolInput, mode, ...) located in packages/shared/src/agent/mode-manager.ts.

According to the source code in mode-manager.ts, the policy logic behaves as follows:

  • In allow-all mode: All tools return allowed: true immediately.
  • In ask mode: Tools return allowed: true but may set requiresPermission: true for commands matching the dangerous-command list.
  • In safe mode: Tools are blocked unless they match a read-only whitelist defined in PermissionsConfigCache.

Dangerous Command Detection

The system maintains a hard-coded DANGEROUS_COMMANDS set in packages/shared/src/agent/core/permission-manager.ts that guarantees high-risk bash commands always require explicit user approval in ask mode. When PermissionManager.checkBashCommand() detects a dangerous pattern, it uses getBashRejectionReason and formatBashRejectionMessage to produce detailed error messages explaining why the command was blocked or requires confirmation.

Session-Scoped Whitelisting

Users can permanently approve specific commands or network domains for the duration of a session. The PermissionManager records these decisions in alwaysAllowedCommands and alwaysAllowedDomains, which bypass standard checks for subsequent invocations. Call permMgr.whitelistCommand('curl') to add a command to the session whitelist, or rely on the UI's "Always Allow" button to populate these sets automatically.

Programmatically Managing Permission Modes

Developers can interact with the permission system directly through the TypeScript API exposed in packages/shared/src/agent/mode-manager.ts and packages/shared/src/agent/core/permission-manager.ts.

Switching Session Modes

Change the active permission mode for a specific session using setPermissionMode:

import { setPermissionMode } from '@/shared/agent/mode-manager';
import { SESSION_ID } from './constants';

setPermissionMode(SESSION_ID, 'ask');

This updates the stored mode value, and the UI reflects the change via the displayName and shortName fields defined in PERMISSION_MODE_CONFIG in mode-types.ts.

Cycling Through Available Modes

To rotate through permission modes programmatically, use cyclePermissionMode which walks PERMISSION_MODE_ORDER = ['safe','ask','allow-all']:

import { cyclePermissionMode } from '@/shared/agent/mode-manager';

cyclePermissionMode(SESSION_ID); // Rotates: safe → ask → allow-all

Evaluating Tool Calls

Instantiate PermissionManager to evaluate specific tool calls against current permissions:

import { PermissionManager } from '@/shared/agent/core/permission-manager';

const permMgr = new PermissionManager({
  sessionId: SESSION_ID,
  workspaceId: WORKSPACE_ID,
  workingDirectory: '/home/user/project',
  plansFolderPath: '/home/user/project/.craft/plans',
});

const result = permMgr.evaluateToolCall('Bash', { command: 'git status' });

if (!result.allowed) {
  console.error('Blocked:', result.reason);
} else if (result.requiresPermission) {
  // Show a prompt to the user before proceeding
}

Whitelisting Commands

Add commands to the session whitelist to bypass future permission checks:

permMgr.whitelistCommand('curl'); // Always allow for subsequent curl invocations

Checking Bash Commands in Safe Mode

Validate specific bash commands before execution:

permMgr.setPermissionMode('safe');
const rejectMsg = permMgr.checkBashCommand('rm -rf /tmp');
if (rejectMsg) {
  console.log('Rejected:', rejectMsg);
}

Summary

  • Craft Agents implement three permission modes—safe (Explore), ask (Ask to Edit), and allow-all (Execute)—defined in packages/shared/src/agent/mode-types.ts.
  • Permission enforcement flows through PermissionManager.evaluateToolCall() in packages/shared/src/agent/core/permission-manager.ts, which delegates to shouldAllowToolInMode() in mode-manager.ts.
  • Safe mode blocks all write operations and restricts tools to a read-only whitelist.
  • Ask mode allows all tools but requires user confirmation for commands listed in DANGEROUS_COMMANDS.
  • Allow-all mode bypasses all checks, enabling fully autonomous agent execution.
  • Session whitelisting via alwaysAllowedCommands and alwaysAllowedDomains persists user approvals for the duration of the session.

Frequently Asked Questions

How do I programmatically change the permission mode in Craft Agents?

Import setPermissionMode from packages/shared/src/agent/mode-manager.ts and call it with the session ID and desired mode key ('safe', 'ask', or 'allow-all'). The function updates the session state and triggers UI updates through the PERMISSION_MODE_CONFIG mapping.

What is the difference between Safe mode and Ask mode in Craft Agents?

Safe mode operates as a read-only sandbox where write operations are blocked entirely, while Ask mode permits write operations but requires explicit user confirmation for commands identified as dangerous in the DANGEROUS_COMMANDS set. Safe mode never prompts the user; Ask mode may prompt depending on the tool being invoked.

Where is the dangerous command list defined in the Craft Agents source code?

The DANGEROUS_COMMANDS set is defined in packages/shared/src/agent/core/permission-manager.ts. This hard-coded list ensures that commands like rm, sudo, and git push always trigger permission requests in Ask mode, regardless of any custom whitelist configurations.

Can I whitelist specific commands for an entire session in Craft Agents?

Yes. The PermissionManager class provides whitelistCommand() and whitelistDomain() methods that add entries to alwaysAllowedCommands and alwaysAllowedDomains respectively. These session-scoped sets bypass standard permission checks for subsequent tool calls, effectively creating a temporary "always allow" policy for approved commands.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →