Skip to content

Permissions

Control which actions require approval to run.

hordecode uses the permission config to decide whether a given action should run automatically, prompt you, or be blocked.

As of v1.1.1, the legacy tools boolean config is deprecated and has been merged into permission. The old tools config is still supported for backwards compatibility.


Actions

Each permission rule resolves to one of:

  • "allow" — run without approval
  • "ask" — prompt for approval
  • "deny" — block the action

Auto mode

Start hordecode with --auto to automatically approve permission requests that are not explicitly denied.

Terminal window
horde --auto

You can also use auto mode with horde run.

Terminal window
horde run --auto "Refactor this module"

Explicit "deny" rules are still enforced. Auto mode only changes requests that would otherwise ask for approval.

In the TUI, open the command palette and select Enable auto-approve permissions or Disable auto-approve permissions to change modes. When auto mode is active, the prompt displays a muted auto indicator next to the current agent.

Auto mode covers the whole running process, including requests raised by subagents, and requests that were already waiting are released when you switch it on. Requests that always ask, such as a shell command that deletes files, still prompt in auto mode; when nobody answers within 60 seconds the request is rejected with a message that tells the model to skip that step and continue. Set HORDECODE_SKIP_ALL_FORCED_ASK_TIMEOUT_MS to change the wait.


Configuration

You can set permissions globally (with *), and override specific tools.

hordecode.json
{
"$schema": "https://hordecode.com/config.json",
"permission": {
"*": "ask",
"bash": "allow",
"edit": "deny"
}
}

You can also set all permissions at once:

hordecode.json
{
"$schema": "https://hordecode.com/config.json",
"permission": "allow"
}

Granular Rules (Object Syntax)

For most permissions, you can use an object to apply different actions based on the tool input.

hordecode.json
{
"$schema": "https://hordecode.com/config.json",
"permission": {
"bash": {
"*": "ask",
"git *": "allow",
"npm *": "allow",
"rm *": "deny",
"grep *": "allow"
},
"edit": {
"*": "deny",
"packages/web/src/content/docs/*.mdx": "allow"
}
}
}

Rules are evaluated by pattern match, with the last matching rule winning. A common pattern is to put the catch-all "*" rule first, and more specific rules after it.

Wildcards

Permission patterns use simple wildcard matching:

  • * matches zero or more of any character
  • ? matches exactly one character
  • All other characters match literally

Home Directory Expansion

You can use ~ or $HOME at the start of a pattern to reference your home directory. This is particularly useful for external_directory rules.

  • ~/projects/* -> /Users/username/projects/*
  • $HOME/projects/* -> /Users/username/projects/*
  • ~ -> /Users/username

External Directories

Use external_directory to allow tool calls that touch paths outside the working directory where hordecode was started. This applies to any tool that takes a path as input (for example read, edit, glob, grep, and many bash commands).

Home expansion (like ~/...) only affects how a pattern is written. It does not make an external path part of the current workspace, so paths outside the working directory must still be allowed via external_directory.

For example, this allows access to everything under ~/projects/personal/:

hordecode.json
{
"$schema": "https://hordecode.com/config.json",
"permission": {
"external_directory": {
"~/projects/personal/**": "allow"
}
}
}

Any directory allowed here inherits the same defaults as the current workspace. Since read defaults to allow, reads are also allowed for entries under external_directory unless overridden. Add explicit rules when a tool should be restricted in these paths, such as blocking edits while keeping reads:

hordecode.json
{
"$schema": "https://hordecode.com/config.json",
"permission": {
"external_directory": {
"~/projects/personal/**": "allow"
},
"edit": {
"~/projects/personal/**": "deny"
}
}
}

Keep the list focused on trusted paths, and layer extra allow or deny rules as needed for other tools (for example bash).


Available Permissions

hordecode permissions are keyed by tool name, plus a couple of safety guards:

  • read — reading a file (matches the file path)
  • edit — all file modifications (covers edit, write, patch; a deny rule also hides multiedit and hashline_edit)
  • glob — file globbing (matches the glob pattern)
  • grep — content search (matches the regex pattern)
  • bash — running shell commands (matches parsed commands like git status --porcelain)
  • task — launching subagents (matches the subagent type)
  • skill — loading a skill (matches the skill name)
  • lsp — running LSP queries (currently non-granular)
  • question — asking the user questions during execution
  • webfetch — fetching a URL (matches the URL)
  • websearch — web search (matches the query)
  • external_directory — triggered when a tool touches paths outside the project working directory
  • doom_loop — triggered when the same tool call repeats 3 times with identical input

Defaults

If you don’t specify anything, hordecode starts from permissive defaults:

  • Most permissions default to "allow".
  • doom_loop and external_directory default to "ask".
  • read is "allow", but reading .env files asks first (.env.example files are allowed):
hordecode.json
{
"permission": {
"read": {
"*": "allow",
"*.env": "ask",
"*.env.*": "ask",
"*.env.example": "allow"
}
}
}

What “Ask” Does

When hordecode prompts for approval, the UI offers three outcomes:

  • once — approve just this request
  • always — approve future requests matching the suggested patterns (for the rest of the current hordecode session)
  • reject — deny the request

The set of patterns that always would approve is provided by the tool (for example, bash approvals typically whitelist a safe command prefix like git status*).


Guardrail profile

ctrl+p, then Agent, Guardrail profile switches between careful, normal and auto.

  • careful asks before edits, shell commands and web fetches even when your rules allow them. A pattern the session has already approved is not asked again, and deny rules still win.
  • The choice is remembered per project and restored on start.
  • Subagents inherit careful mode and only the approvals their parent gave.

Audit log

With HORDECODE_PERMISSION_AUDIT=1 (or the permission_audit switch), every permission decision and reply is written as one JSON line to <data>/log/permission.jsonl. The file rotates at 5 MiB (HORDECODE_PERMISSION_AUDIT_MAX_BYTES) and keeps three older files.

Each line carries prev, the SHA-256 of the line before it, and the chain continues across rotation. horde debug audit-verify [file] walks the files oldest first and reports the first line that does not match, so a line that was edited or removed in the middle of the log is found. Lines written before the chain existed are counted as legacy.

The chain is a local integrity check without a secret key, which sets its scope:

  • Someone who can write the file can also rewrite the whole chain consistently. Keep the log where only you can write, or copy it elsewhere if you need tamper evidence against other users.
  • Lines removed from the end of the newest file leave a shorter, valid chain.
  • When the oldest file rotates out, the first remaining line becomes the start of the chain.
  • Two hordecode processes writing to the same log at the same time can interleave lines and break the chain; verify reports the first such line.

Agents

You can override permissions per agent. Agent permissions are merged with the global config, and agent rules take precedence. Learn more about agent permissions.

hordecode.json
{
"$schema": "https://hordecode.com/config.json",
"permission": {
"bash": {
"*": "ask",
"git *": "allow",
"git commit *": "deny",
"git push *": "deny",
"grep *": "allow"
}
},
"agent": {
"build": {
"permission": {
"bash": {
"*": "ask",
"git *": "allow",
"git commit *": "ask",
"git push *": "deny",
"grep *": "allow"
}
}
}
}
}

You can also configure agent permissions in Markdown:

~/.config/hordecode/agents/review.md
---
description: Code review without edits
mode: subagent
permission:
edit: deny
bash: ask
webfetch: deny
---
Only analyze code and suggest changes.