Docs/Advanced: command line/Permissions & Security

Permissions & Security

Dynamo's permission system balances safety with speed.

Permission Levels

LevelBehaviorExamples
SafeAuto-execute, no promptread_file, list_files, search_files, git_status, memory_list
WritePrompts once per tool, per model (persists for the session)write_file, edit_file, git_commit, web_fetch
DangerousPrompts every time. "Allow every" is never offered, and no earlier grant covers it.run_command (every command — ls as much as rm), move_file, rename_file, delete_file, checkpoint_restore, job_kill; git_push to a protected branch, with a force flag, deleting a branch, or to a remote this repo doesn't have; git_lfs_unlock with force
BlockedNever runs, in any modeShell strings with sudo, command substitution ($(), backticks), parameter expansion (${}), or process substitution (<(…), >(…)); any force-push to a protected branch, by run_command or git_push

Some calls ask every time, even in Auto Mode: writes to protected files (see below), checkpoint_restore, checkpoint_delete, job_kill, turning a skill back on, a force-push to a protected branch you have allowed, and edits during a compile-error cascade.

Protected branches

A protected branch is the repository's default branch (the remote's HEAD; main or master when that is unknown), any branch matching a permissions.protected_branches pattern in dynamo.yaml (names or globs like release/*), or a branch GitHub marks protected.

Any force-push to a protected branch is blocked: -f, --force, --force-with-lease, --force-if-includes, a + refspec, --mirror or a forced --all, in any argument order, through git_push or run_command. Auto Mode and grants can't run it. To allow it, set permissions.allow_force_push_protected: true in dynamo.yaml. It then asks every time instead, even in Auto Mode, and never offers "Allow every".

A plain push to a protected branch is dangerous: it asks every time, but Auto Mode approves it.

Grants are stored per tool + model. A grant never covers a dangerous call. git_push and git_lfs_unlock set their level per call, so a grant you give on an ordinary push still asks again before a push to a protected branch like main, a force-push, a branch deletion, or a push to a remote this project doesn't know. A grant on git_lfs_unlock still asks before unlocking a file someone else locked. Grants survive /resume.

Approval Menu

An approval card in the chat with Allow and Don't allow
In the app: an approval card

When a tool requires approval, you see:

  • ●Human-readable description of what the tool will do
  • ●Expandable raw call details (press → to expand)
  • ●Diff view for file edits with line numbers and colored +/- lines
  • ●Allow / Allow every … (model) / Deny options. "Allow every" is not offered when the call is dangerous or always asks.

"Allow every" is scoped per tool, per model. Allowing file writes for Claude doesn't allow them for GPT. Switching models and switching back keeps your approvals. Approvals persist across session resume.

Auto Mode

The Mode menu in the chat box with Ask first and Auto Mode
In the app: the Mode menu
Settings → Permissions: where new chats start, where Dynamo can work, and force-pushing to protected branches
In the app: Settings → Permissions
bash
dynamo -y
dynamo --auto

Auto Mode approves the whole dangerous tier, not just routine writes — every run_command sits in that tier, ls as much as rm, because Dynamo doesn't rank shell commands against each other. Turning it on is one trust decision about the shell.

Auto Mode's own description: "Changes run without asking. Dynamo still asks before it touches protected files like .env or keys, restores or deletes a checkpoint, stops a job, turns a skill back on, force-pushes to a protected branch you allowed, and during a compile-error cascade. Blocked commands never run."

  • ●Blocked commands — never run.
  • ●Protected files like .env or keys — still ask.
  • ●Restoring or deleting a checkpoint — always asks.
  • ●Stopping a job (job_kill) — always asks.
  • ●Turning a skill back on — always asks.
  • ●Force-pushing to a protected branch you allowed — always asks.
  • ●A compile-error cascade — editing tools ask for the rest of the turn.

Per-Model Permissions

Permissions are tracked as a per-model map. Each model has its own set of "Allow every" grants — granting write_file for Claude doesn't auto-grant it for GPT, so a more powerful model never inherits a weaker one's approvals. Switching models doesn't wipe any model's grants: switch away and back and your previous approvals are still there. Grants also persist across session resume.

Sandbox Mode

Controls filesystem access for all tools including shell commands.

Moderead_filewrite/editlist/searchrun_command
projectproject onlyproject onlyproject onlyblocks paths outside the project
full (default)project onlyproject onlyanywhereblocks paths outside the project
unrestrictedanywhereanywhereanywhereno path checks (still permission gated)

Set via CLI (--sandbox project), config (ai.sandbox: project), or at runtime (/sandbox).

In project and full mode, shell commands that reference paths outside the project are blocked. So are inline interpreter code (python -c, node -e, heredocs) and eval, because their paths can't be checked. Only unrestricted lifts this. sudo is always blocked regardless of sandbox mode.

Checkpoints

Dynamo snapshots your work before risky operations so you can roll back.

  • ●Auto-snapshot — taken once per prompt, before the first write_file/edit_file and before a destructive run_command
  • ●Rollback modes — code (restore files only), conversation (rewind history only), or both
  • ●Retention — checkpoints are stored under your config dir, per project, and pruned after 30 days
  • ●Manage — run /checkpoint for an interactive overlay to list, create, or restore. The model can also call checkpoint_list / checkpoint_create / checkpoint_restore.

Security Hardening

  • ●Command injection detection — command substitution ($(), backticks), parameter expansion (${}), and process substitution (<(…), >(…)) are always blocked
  • ●Compound command splitting — cmd1 && cmd2 — each part checked independently
  • ●Protected files — writes to .env, .env.*, .git/config, .git/hooks/*, .gitconfig, .bashrc, .zshrc, .profile, .bash_profile, .ssh/*, .npmrc, credentials.json, id_rsa*, *.pem and *.key always ask first, even in Auto Mode. Most patterns are anchored at the project root, so a nested apps/api/.env is not covered (*.pem / *.key match by suffix at any depth).
  • ●Secret scanning — secrets are blocked outright in memory_save, warned on write_file, and noted on read_file