Permissions Reference¶
The permission system controls what the agent can do without asking. Each mode has its own rules, and the prompt that appears when a tool is gated offers several scopes for approving the call.
How Rules Work¶
Permissions exist so you can trade safety for speed. In a trusted codebase you
might auto-approve every git command; on an unfamiliar repo you may want the
agent to ask before every edit. The system lets you set these boundaries per
mode, per tool, and per workspace.
Permissions are split between tool-level rules and pattern-level
rules. The tool name (bash, edit_file, web_fetch, …) decides whether the
call needs gating at all; pattern buckets (bash, web_fetch, mcp, and any
tool that registers its own bucket) further refine the decision based on the
call's arguments.
Each rule list has three slots:
- allow: execute silently
- ask: prompt for confirmation
- deny: block (deny always wins over allow and ask)
Patterns are globs. For pattern rules, the most specific (longest) matching pattern wins; on a tie, ask beats allow. Anything not matched falls back to tool, effect, and mode defaults.
Default Tool Permissions¶
| Tool | Normal | Plan | Apply | Yolo |
|---|---|---|---|---|
read_file |
Allow | Allow | Allow | Allow |
glob |
Allow | Allow | Allow | Allow |
grep |
Allow | Allow | Allow | Allow |
ask_user_question |
Allow | Allow | Allow | Allow |
edit_file |
Ask | Deny | Allow | Allow |
write_file |
Ask | Deny | Allow | Allow |
edit_notebook |
Ask | Deny | Ask | Allow |
bash |
Ask | Allow / Ask / Deny | Ask | Allow |
web_fetch |
Ask | Ask | Ask | Allow |
web_search |
Ask | Ask | Ask | Allow |
read_process_output |
Allow | Allow | Allow | Allow |
enter_worktree |
Ask | Ask | Ask | Allow |
stop_process |
Ask | Deny | Ask | Allow |
load_skill |
Ask | Ask | Ask | Allow |
present_plan |
N/A | Allow | N/A | N/A |
smelt_reload |
Ask | Deny | Ask | Allow |
Plan mode is built in. It ships with a read-only default policy and adds the
present_plan tool. Read-only tools stay allowed, enter_worktree and unknown
or networked tools require confirmation, and write/process/config effects are
denied without prompting unless your config extends the policy differently.
Default Bash Patterns¶
Read-only commands with no side effects are allowed by default. Commands that can modify files, install packages, or affect system state require approval.
| Pattern | Normal | Apply | Yolo |
|---|---|---|---|
ls * |
Allow | Allow | Allow |
find * |
Allow | Allow | Allow |
tree * |
Allow | Allow | Allow |
cat * |
Allow | Allow | Allow |
head * |
Allow | Allow | Allow |
tail * |
Allow | Allow | Allow |
less * |
Allow | Allow | Allow |
grep * |
Allow | Allow | Allow |
sort * |
Allow | Allow | Allow |
uniq * |
Allow | Allow | Allow |
wc * |
Allow | Allow | Allow |
diff * |
Allow | Allow | Allow |
tr * |
Allow | Allow | Allow |
cut * |
Allow | Allow | Allow |
jq * |
Allow | Allow | Allow |
echo * |
Allow | Allow | Allow |
pwd * |
Allow | Allow | Allow |
which * |
Allow | Allow | Allow |
dirname * |
Allow | Allow | Allow |
basename * |
Allow | Allow | Allow |
realpath * |
Allow | Allow | Allow |
stat * |
Allow | Allow | Allow |
file * |
Allow | Allow | Allow |
test * |
Allow | Allow | Allow |
du * |
Allow | Allow | Allow |
df * |
Allow | Allow | Allow |
date * |
Allow | Allow | Allow |
whoami * |
Allow | Allow | Allow |
sha256sum * |
Allow | Allow | Allow |
md5sum * |
Allow | Allow | Allow |
xxd * |
Allow | Allow | Allow |
hexdump * |
Allow | Allow | Allow |
strings * |
Allow | Allow | Allow |
| other | Ask | Ask | Allow |
Compound commands split on shell operators (&&, ||, ;, |) are evaluated
per subcommand; the worst decision wins, and a single deny blocks the whole
command. cd is always allowed.
Note
In modes whose metadata enables ask_on_output_redirection (Normal and Plan by default),
otherwise-allowed bash commands that contain output redirection (>, >>, &>)
are escalated to Ask. Plan mode's read-only policy then denies redirections that
write to real files.
Configuring Permissions¶
Extend the generated policy in init.lua with smelt.permissions.extend:
smelt.permissions.extend({
default = {
tools = {
allow = { "web_search" },
},
effects = {
network = "ask",
write = "ask",
},
patterns = {
web_fetch = {
allow = { "https://docs.rs/*" },
},
bash = {
allow = { "git log *", "git diff *" },
},
},
},
apply = {
patterns = {
bash = {
allow = { "git commit *" },
},
},
},
})
default applies to all registered modes. Mode-specific rules are keyed by mode
name (normal, apply, yolo, or plugin-registered names such as plan) and
are merged on top of the generated base policy.
Each mode table can contain:
| Key | Value |
|---|---|
tools |
{ allow = {...}, ask = {...}, deny = {...} }, tool names |
effects |
{ read|write|network|process|config|user|other = decision } |
patterns |
Tool-specific { allow = {...}, ask = {...}, deny = {...} } buckets |
Pattern buckets are routed through the matching tool's parser. Built-in buckets
include bash (shell-aware parsing), web_fetch (URL glob), and mcp (matched
against servername_toolname); tools that register their own bucket appear here
too.
The Permission Prompt¶
When a call is gated, a confirm dialog appears with the tool summary, a preview
(when available, for example a diff for edit_file), and these options:
| Option | Effect |
|---|---|
| yes | Approve this call only |
| no | Deny this call (and Esc does the same) |
allow <pattern> |
Auto-approve calls matching <pattern> for this session |
allow <pattern> in cwd |
Same, persisted to this workspace |
| always allow | Auto-approve any call to this tool for this session |
| always allow in cwd | Same, persisted to this workspace |
<pattern> is the tool-specific approval pattern (e.g. a shell command stem
like git status for bash, or a URL host for web_fetch). When the call
touches a path outside the workspace, the dir-based options (allow <dir> /
allow <dir> in cwd) appear instead.
Press e to add a freeform reason that the model will see along with your
decision.
Approval Scopes¶
The "always allow" options above approve future calls at one of two scopes:
| Scope | Lifetime | Storage |
|---|---|---|
| Session | Until /clear, /new, or exit |
Memory |
| Workspace | All future sessions in this CWD | $XDG_STATE_HOME/smelt/workspaces/<cwd>/permissions.json |
Workspace approvals stay narrow: approving a command pattern only approves calls matching that pattern, and approving an outside directory only approves access under that directory.
Managing Saved Approvals¶
Use /permissions to view and remove session/workspace approvals:
j/kto navigateddorBackspaceto delete the highlighted entryEscto close (changes are persisted on close)
Workspace Restriction¶
When restrict_to_workspace is enabled (default), any tool call targeting a
path outside the current workspace has its decision downgraded from Allow to
Ask, even if the call would otherwise have been auto-approved by tool, bash
pattern, or runtime approval. This catches mistakes like the agent editing a
file in your home directory when it meant to edit one in the project root. The
prompt then offers per-directory approval options.
Warning
Best-effort safety measure. Shell commands, symlinks, and indirect access can bypass workspace restriction.
Project Trust¶
.smelt/ content (init.lua, plugins/, commands/, runtime/) is only
loaded after the user explicitly trusts the project. Run /trust from the
project root to record a SHA-256 hash of the current .smelt/ contents; on next
startup smelt loads the directory if the hash still matches. Editing any trusted
file invalidates the hash and requires re-running /trust.
Trust state is stored in $XDG_STATE_HOME/smelt/trust.json, keyed by canonical
project path. See smelt.trust for the Lua API.
Secret Redaction¶
When redact_secrets is enabled, smelt scrubs detected secrets from
user-submitted text and tool output, including command lines and file contents
shown in the confirm prompt, before they reach the LLM or the transcript. This
matters because LLM providers may log or train on prompts; redaction lowers the
risk of accidentally leaking API keys or tokens into a third-party system.
Enable it with:
Headless Mode¶
In --headless, there is no interactive prompt: calls that would be Ask are
denied. To run autonomously, combine headless with --mode yolo. See the
Headless Mode guide.
Isolation¶
Permissions and workspace restriction guard against accidental mistakes, not
against an agent that actively tries to escape. Any approved bash command runs
with your user's privileges, so a script like rm -rf ~ works exactly as it
would if you typed it yourself.
For untrusted prompts, models, or MCP servers, run smelt inside a container or VM. Anything else is defense in depth, not a sandbox.