Skip to content

Permission model

Every tool call is checked against the active permission policy before execution. The policy is layered: a per-tool check trait, a structured decision protocol, persistent allow/deny/ask rules, and a bash-compound splitter that classifies each && / | / ;-joined segment independently.

The five user-facing modes

ModeBehavior
defaultPrompt for file changes and shell access.
planRead-only — file-mutating tools are blocked.
acceptEditsAuto-approve workspace edits; prompt for shell access.
bypassPermissionsUnrestricted tool access.
dontAskAuto-approve everything without prompting (allow/deny rules still apply).

Set the mode at launch:

Terminal window
lime --permission-mode plan
lime --dangerously-skip-permissions # forces bypassPermissions

…or inside the REPL:

/permissions acceptEdits

…or in user/local config:

{ "permissions": { "defaultMode": "acceptEdits" } }

Per-tool allow / deny / ask

Project config can shape the prompt-vs-auto behavior per tool:

.lime.json
{
"permissions": {
"allow": ["read_file", "glob_search", "grep_search"],
"ask": ["write_file", "edit_file"],
"deny": ["bash"]
}
}

Values can be:

  • A bare tool name — "bash" matches every bash invocation.
  • A patterned form — "Bash(git status:*)" matches the bash tool with any input starting git status.
  • A scoped tool form — "Edit(.git/**)" matches edits whose path matches the glob.

Patterns support * / ? glob wildcards or plain substring matching against the tool name, raw input, or the combined tool_name:input string.

Bash compound splitter

bash invocations are pre-split: each segment between &&, ||, |, or ; is classified independently. A compound like git status && rm -rf node_modules evaluates git status (allowed) and rm -rf node_modules (potentially denied) separately.

Plan mode

plan mode blocks every WriteWorkspace and FullAccess tool except writes to the active plan file. The model can still read the workspace, search, and reason; it cannot mutate. To leave plan mode, the model calls exit_plan_mode, which surfaces a confirmation prompt.

The trusted-settings pin

Two settings always resolve from User + Local config (and the optional Policy layer), never from project config:

  • permissions.defaultMode
  • mcpServers (the startup MCP set)

This prevents a checked-in .lime.json from silently lowering trust on a teammate’s machine. If a project file defines either field, Lime emits a diagnostic warning and ignores the project value for trust resolution. The non-trust portion of the project config (allow/deny/ask, hooks, plugins, sandbox) merges normally.

Resolution order

The merged policy resolves in this order, highest precedence last:

  1. Policy — managed enterprise/policy file at LIME_MANAGED_SETTINGS.
  2. User~/.lime/settings.json, ~/.lime/config.toml.
  3. Project.lime.json, .lime/settings.json, .lime/config.toml.
  4. Local.lime/settings.local.json, .lime/settings.local.toml.
  5. CLI flags--settings FILE_OR_JSON, --permission-mode, --dangerously-skip-permissions.

Within each scope, TOML wins over JSON on overlap. Use --setting-sources to restrict which scopes are merged (useful for tests and reproducing other people’s environments).

Decision protocol

When a tool call requires approval, the policy returns a structured PermissionDecision with one of:

  • allow — proceed.
  • deny — abort with the recorded reason.
  • ask — surface a UI prompt to the user.

Each decision carries a reason and a source (which rule, which scope) so /status and /config can explain why a particular call was treated the way it was.

See also

  • Exec rules — persistent allow/deny rules outside the config file.
  • Sandboxing — process isolation for the most dangerous calls.
  • HooksPreToolUse hooks can override the policy at call time.