Permissions
Luna uses a multi-layered permission system: permission modes (global), per-mode rulesets (fine-grained), danger detection (regex-based), and an optional AI classifier (LLM-based).
Permission Modes
Five modes control which tools the agent can use. Set via CLI flag, config file, or TUI.
| Mode | Description |
|---|---|
default | Standard mode. Per-mode rulesets determine allow/deny/ask per tool. |
allow-all | No restrictions. All operations proceed without checks. |
deny-all | Agent can only reason -- no tool execution at all. |
read-only | Only read-category tools allowed (read_file, glob_search, grep_search, etc.). |
auto | AI classifier evaluates "ask" decisions automatically when confidence >= 0.85. |
Setting Permission Mode
luajit client/main.lua --permission-mode default
luajit client/main.lua -p auto
luajit client/main.lua -p allow-allConfig file (~/.luna/config.json):
{
"permission_mode": "auto"
}TUI slash command:
/autoPer-Mode Rulesets
Each agent mode has a built-in permission ruleset that maps tool names to allow, deny, or ask.
Build Mode
| Tool | Decision | Notes |
|---|---|---|
read_file, glob_search, grep_search, list_directory, web_fetch, lsp, web_search, todo, fuzzy_edit | allow | Read/search always allowed |
bash | ask | User approval required |
write_file | ask (except *.md -> allow) | File pattern matching supported |
edit_file, create_directory, undo_edit | ask | User approval required |
delete_file | deny | Always blocked |
Plan Mode
| Tool | Decision |
|---|---|
| Read/search/web tools | allow |
* (default) | deny |
Explore Mode
| Tool | Decision |
|---|---|
| Read/search/lsp tools | allow |
* (default) | deny |
Review Mode
| Tool | Decision |
|---|---|
| Read/search/lsp/web tools | allow |
web_fetch | ask |
* (default) | deny |
General Mode
| Tool | Decision |
|---|---|
* (default) | allow |
bash | ask |
delete_file | ask |
Coordinate Mode
| Tool | Decision |
|---|---|
* (default) | allow (orchestrator needs full access) |
File Pattern Matching
Rulesets support file pattern matching for tools that take file paths:
{
"write_file": {
"default": "ask",
"patterns": {
"*.md": "allow",
"*.env": "deny"
}
}
}Patterns use glob syntax: *.ext, path/prefix*, etc.
Danger Detection
Before evaluating the ruleset, the danger detector scans bash commands against 41 regex patterns across 8 categories:
| Category | Example | Default Severity |
|---|---|---|
| Destructive delete | rm -rf /, rm -rf ~ | dangerous |
| Remote code execution | curl | bash, wget | sh | dangerous |
| System control | shutdown, halt, poweroff | dangerous |
| Privilege escalation | sudo, chmod 777 | caution |
| Network exfiltration | scp, rsync to remote | caution |
| File removal | rm - with flags | caution |
Override behavior:
dangerousoverridesallowtodenycautionoverridesallowtoask
Shell Quoting
All shell arguments are wrapped using cel.shell_quote (single-quote wrapping) to prevent injection from LLM-generated parameters. This blocks $(), backticks, $VAR expansion, and other shell metacharacters.
AI Classifier (Auto Mode)
When permission_mode is auto, an Ollama-hosted LLM classifies "ask" decisions:
Tool invocation -> Ruleset -> "ask"
|
+-- AI classifier available?
| +-- Yes -> Classify (5s timeout)
| | +-- confidence >= 0.85 -> auto allow/deny
| | +-- confidence < 0.85 -> TUI dialog
| +-- No -> TUI dialog
+-- Not auto mode -> TUI dialogConfiguration
{
"classifier": {
"enabled": true,
"model": "qwen2.5-coder:7b",
"provider": "ollama",
"base_url": "http://localhost:11434",
"confidence_threshold": 0.85,
"timeout": 5,
"cache_size": 64
}
}| Setting | Default | Description |
|---|---|---|
enabled | false | Global enable/disable |
model | qwen2.5-coder:7b | Classifier model (fast local recommended) |
confidence_threshold | 0.85 | Minimum confidence for auto-decision |
timeout | 5 | Seconds before fallback to dialog |
cache_size | 64 | LRU cache entries for repeated invocations |
Safety Guarantees
The classifier never blocks tool execution on failure:
| Scenario | Behavior |
|---|---|
| Classifier model unavailable | Show TUI dialog |
| Request timeout (>5s) | Show TUI dialog |
| Response unparseable | Show TUI dialog |
| Confidence below threshold | Show TUI dialog |
Environment Overrides
| Variable | Description |
|---|---|
LUNA_CLASSIFIER_ENABLED | "true" / "false" |
LUNA_CLASSIFIER_MODEL | Override classifier model |
LUNA_CLASSIFIER_PROVIDER | Override classifier provider |
LUNA_CLASSIFIER_THRESHOLD | Override confidence threshold (0.0--1.0) |
Permission Evaluation Flow
1. Global mode check
+-- allow-all -> execute immediately
+-- deny-all -> block immediately
+-- read-only -> only allow read-category tools
2. Mode ruleset evaluation
+-- allow -> execute
+-- deny -> block
+-- ask -> danger analysis
+-- dangerous -> deny (override)
+-- caution + allow -> ask (upgrade)
+-- ask -> permission_mode check
+-- auto -> AI classifier
+-- other -> TUI permission dialog
3. TUI dialog -> user approves/deniesMutation Queue
Write operations (write_file, edit_file, delete_file) are serialized through a mutation queue. This prevents race conditions when the agent executes multiple concurrent tool calls that modify the same files.
Tool Restrictions
Tools can be restricted for sub-agents spawned via the task tool. Pass a tools array to limit the sub-agent to a subset of available tools:
{
"prompt": "Read the README and summarize it",
"tools": ["read_file", "glob_search"]
}Teammate agents spawned via team_spawn run with restricted permissions (no sub-agent, no memory).