Skip to content
LoopCodeDocs

Concepts

Permissions and safety

How LoopCode decides what it may do on its own — approval modes, auto-review, permission rules, the OS sandbox, and running unattended.

Approval modes

ModeSetting valueWhat happens
Auto-review (default)autoRoutine work goes ahead. Each action no rule covers is judged by a reviewer; you are asked only when it should ask
Auto-approve editsacceptEditsFile edits go through; commands still ask
Ask before changesdefaultEvery edit and command waits for you
Plan modeplanRead-only. LoopCode explores and proposes a plan for you to approve

Change the mode with shift tab in the terminal, the mode picker in the app, --mode <value> on the command line, or defaultMode in settings. The composer always shows the mode in force.

Whatever the mode, file edits are shown as diffs you can undo, and git commits, branch changes and other repository writes ask for approval.

Auto-review

Asking about every command is what makes an agent slow; approving them in bulk is what makes it dangerous. Auto-review judges each action instead:

  1. A fixed policy first. Known-safe reads and checks go through at once. A handful of catastrophic commands never do.
  2. Then a reviewer model, in two stages. A quick check that leans towards blocking, and — only for what it flags — a careful one that weighs the action's risk against what you actually asked for. The reviewer sees your messages and the agent's actions, but not the agent's own reasoning or its tools' output, so a malicious file or web page cannot talk it into anything.
  3. When in doubt, ask. If the reviewer is unavailable or its answer is unclear, LoopCode asks you. It never falls back to allowing.

Tune the policy

See the baseline policy:

bash
loopcode auto-review defaults

It lists the trusted environment, what is blocked unless you asked for exactly that, and what is allowed even so. Add to it in your settings:

~/.loopcode/settings.json
{
  "autoReview": {
    "environment": ["github.com/your-org", "s3://your-team-bucket"],
    "block": ["dropping any database table"],
    "allow": ["deploying to the staging environment"]
  }
}

A repository's committed .loopcode/settings.json may only add to block. What you trust, and what is excepted, come from your own files.

Answering a permission request

When LoopCode asks, you can:

  • Allow once — this call only.
  • Allow for this session — calls like it, until the session ends.
  • Always allow — written as a rule to .loopcode/settings.local.json, your personal file for this project, where you can read and edit it.
  • Deny — and LoopCode takes another approach.

For a command, the remembered rule covers the runner and its subcommand — npm test, git commit — or the program alone, never an arbitrary command that happens to start the same way.

Permission rules

Rules live in settings files, so a team can commit the ones that apply to everyone and keep personal ones local. They use the syntax Claude Code uses:

.loopcode/settings.json
{
  "permissions": {
    "allow": ["Bash(npm run test:*)", "Bash(npm run lint)", "Edit(src/**)"],
    "ask": ["Bash(git push:*)"],
    "deny": ["Read(./.env)", "Read(./secrets/**)", "WebFetch(domain:internal.example.com)"],
    "additionalDirectories": ["../shared-config"]
  }
}
RuleMatches
BashEvery use of the tool
Bash(npm run test:*)A command prefix. :* and a trailing * mean the same thing
Read(./.env)A path, in gitignore syntax. A bare file name matches it anywhere
Edit(src/**)Everything under a directory
WebFetch(domain:docs.example.com)A host, including its subdomains
Browser(action:open)A top-level input parameter

Rules are evaluated deny → ask → allow, and the first match in that order decides. A broad deny therefore beats a narrow allow. A command prefix rule never matches a command that chains or substitutes other commands (;, &&, |, `, $(…), redirection).

Rules from all settings files accumulate rather than replace each other, so a project can forbid something that a personal file cannot allow back. /permissions lists the rules in force, and where each came from.

Sandbox

The sandbox lets the operating system — not the model, and not a prompt — decide what a shell command can touch. A command that cannot leave the workspace or reach the network does not need a person to vet it.

.loopcode/settings.json
{
  "sandbox": {
    "enabled": true,
    "allowUnsandboxedCommands": true,
    "filesystem": { "allowWrite": ["/tmp/build-cache"], "denyRead": ["~/.ssh"] },
    "network": { "enabled": false }
  }
}
FieldDefaultMeaning
enabledfalseRun shell commands inside the sandbox
allowUnsandboxedCommandstrueLet a command the sandbox refused be retried outside it, with the usual approval
filesystem.allowWrite—Extra paths commands may write to, beyond the workspace
filesystem.denyRead—Paths commands may not read
filesystem.disabled—Turn the filesystem restriction off
network.enabledfalseAllow network access. Off by default: most builds and tests need none, and sending data out is the real risk

macOS uses the built-in Seatbelt framework, so there is nothing to install. Linux uses bubblewrap when it is installed. Elsewhere the sandbox reports itself unavailable, and commands go through the normal approval flow rather than running unprotected.

Protected by default

  • File listings and searches skip sensitive paths, dependency folders and version-control internals.
  • WebFetch refuses private, loopback and cloud-metadata addresses.
  • Custom language servers are read only from your own ~/.loopcode/settings.json, never from a repository's files. See Code intelligence.

Running unattended

In headless mode, nobody is there to answer, so a permission no rule or mode covers is denied. Give a CI job the rules it needs rather than switching checks off.

FlagEffect
-y, --yesApprove every permission a headless run asks for
--dangerously-skip-permissionsNothing asks before acting, in any mode