1. R-CLI
  2. Permissions

Permissions decide what R-CLI may do without asking you. Read-only work runs freely; anything that changes your machine asks first, unless you have said otherwise.

By default R-CLI starts in Manual mode: it reads files and runs safe commands on its own, and asks before every edit, write, or non-trivial shell command.

​
Permission modes

Press Shift+Tab to cycle modes during a session. The current mode is shown in the status bar.

ModeIndicatorBehavior
manual⏸ ManualDefault. Asks before anything that is not read-only or explicitly allowed.
acceptEdits◆ Accept EditsFile edits and writes inside your project folder run without asking. Shell commands and everything else still ask.
auto✦ AutoReserved for automatic classification. Today it behaves like manual.
bypass» BypassRuns everything except deny and ask rules. Not in the Shift+Tab cycle.

Set the mode at startup instead:

backboard --permission-mode acceptEdits

bypass mode lets the agent run any command and edit any file without asking, including outside your project folder. Use it only in throwaway environments such as containers or CI. It is deliberately unreachable from Shift+Tab — you must pass the flag or set it in config.

An unrecognized value does not stop the run. R-CLI falls back to manual and prints a warning:

Unknown --permission-mode "yolo"; using manual mode. Valid: manual, acceptEdits, auto, bypass.

​
Configuration file

Permission settings live in your project, at the repository root:

<repo-root>/.backboard/settings.json

The repo root is found by walking up from your working directory looking for .git, so every subdirectory of a project shares one policy.

{
  "permissions": {
    "mode": "manual",
    "allow": [
      "execute(git status:*)",
      "execute(bun test:*)",
      "read(src/**)"
    ],
    "deny": [
      "execute(rm:*)",
      "write(.env)"
    ],
    "ask": [
      "execute(git push:*)"
    ]
  }
}
KeyTypeDescription
modestringStarting permission mode. Overridden by --permission-mode.
allowstring[]Rules that run without asking.
denystring[]Rules that are always blocked.
askstring[]Rules that always prompt, even in bypass mode.

Mode precedence is --permission-mode flag, then permissions.mode, then manual.

A missing or malformed settings.json is treated as empty settings — R-CLI falls back to defaults rather than failing to start.

​
Rule syntax

A rule is a tool name, optionally followed by a pattern in parentheses:

execute                      # the whole Execute tool
execute(git status:*)        # commands starting with "git status"
write(.env)                  # writing exactly .env
read(src/**)                 # reading anything under src/

Tool names are lower-cased, for example execute, read, write, edit, find_skill, find_mcp.

Patterns are matched against the meaningful part of the call — the command string for execute, the file path for edit and write:

Pattern formMatches
prefix:*Content equal to prefix, or starting with prefix followed by a space
Contains *Glob match, for example read(src/**)
Anything elseExact string equality

prefix:* matches on whole space-delimited tokens, not raw text. execute(git:*) allows every git subcommand, including git push and git reset --hard. Scope allow rules as tightly as you can.

​
How a decision is made

For every tool call, the first matching step wins:

1

Deny rule

A matching deny rule blocks the call. Nothing overrides this.

2

Ask rule

A matching ask rule always prompts, even in bypass mode.

3

Tool verdict

Some tools decide for themselves. In acceptEdits mode, Edit, Write, and ApplyPatch approve paths inside the directory R-CLI was started in — not the whole repository. A symlink that resolves outside that directory is still rejected.

4

Read-only check

Tools that only read are allowed automatically, in every mode.

5

Bypass mode

In bypass mode, everything remaining is allowed.

6

Allow rule

A matching allow rule permits the call.

7

Otherwise, ask

Anything unmatched prompts you.

deny and ask are evaluated before the bypass gate on purpose: no mode can skip them. This makes deny a reliable guardrail even in automated runs.

​
Safe commands

Some read-only shell commands are approved automatically without a rule:

git status   git diff   git log   git show
ls   pwd   cat   head   tail   wc   which   echo
grep   rg   find
bun test   bun run typecheck

Read-only forms of git branch are also approved — --list, --show-current, -a, -r, -v, and their combinations.

These are treated as unsafe and will still prompt:

  • Anything containing $(, a backtick, >, or <.
  • Chained commands where any segment is not itself safe — segments are split on &&, ||, ;, |, &, and newlines.
  • find with -exec, -execdir, -ok, -okdir, -delete, -fprint, -fprintf, -fprint0, or -fls.
  • rg with --pre, --pre-glob, --hostname-bin, --search-zip, or -z.
  • git status, git diff, git log, or git show with --output.
  • git branch with anything other than read-only flags such as --list or --show-current. A bare branch name mutates, so it prompts.
  • Background commands, which are never auto-approved by the safe list.

Quotes are stripped before the find, rg, and git flag checks, so '-delete' cannot dodge the guard. The $(, backtick, >, and < check runs on the raw command.

​
The permission prompt

When a call needs approval, R-CLI shows the tool, a one-line summary of what it will do, and three choices:

ChoiceEffect
Yes, allow onceRuns this one call.
Yes, always allow (<rule>)Runs it and saves the shown rule to settings.json.
No, denyBlocks the call and tells the agent.

The “always allow” option always shows the exact rule it will save, so you can see how broad it is before accepting.

R-CLI scopes that rule conservatively:

Command shapeSaved rule
A single path-like argumentExact path, for example write(src/index.ts)
A sensitive commandThe exact full command, never a prefix
Anything elseFirst two tokens, for example execute(bun test:*)

Sensitive commands that never generalize include rm, rmdir, mv, dd, mkfs, ln, chmod, chown, chgrp, curl, wget, kill, killall, pkill, sudo, su, git, docker, ssh, scp, and rsync. Approving rm -rf build once will not allow rm in general.

This list is best-effort rather than exhaustive. Prefer an explicit deny rule for anything you never want run.

​
Headless and automation

Non-interactive runs cannot show a prompt, so anything that would ask is denied:

Permission required for Execute — permission prompts are unavailable in this context.

This applies to --print one-shot mode. To script R-CLI, either pre-approve exactly what it needs:

{
  "permissions": {
    "allow": ["execute(bun test:*)", "execute(git diff:*)"],
    "deny": ["execute(git push:*)"]
  }
}

Or, in a disposable environment only:

backboard --print "run the test suite" --permission-mode bypass

Pairing bypass with a deny list is safer than bypass alone. Deny rules still apply, so you can block destructive commands while letting everything else run unattended.

​
Sub-agents

Sub-agents inherit the parent session’s mode and rules, but can never prompt. Each of their tool calls is checked individually, and anything that would ask is denied.

Sub-agents also cannot install third-party code. They can call the skill and MCP discovery tools, but those tools refuse to install anything from a sub-agent and report the match back instead. Only the main agent can request an install, and only with your confirmation.