The short answer
Windsurf’s Cascade agent has four auto-execution levels for terminal commands: Disabled, Allowlist Only, Auto and Turbo.1 Disabled asks before every command. Allowlist Only runs listed commands and asks for the rest. Auto lets the model judge which commands are safe, and only for messages sent with premium models. Turbo runs every command except those on your deny list.1 A deny-list match doesn’t block a command; it makes Cascade ask.1 If you need a command to never run, write a pre_run_command hook that exits with code 2.2
Deedglass
A tool call meets your rules before it runs
Asks to run
DELETE FROM visits;
Deletes every row in visits
Deedglass checks your rules
- Reading dataAllowed
- Deleting a whole table (DROP, TRUNCATE)Never
- Changing or deleting rows without saying which (WHERE)This one
- Other changesWait for a person
A note on the name
Windsurf’s documentation now lives on docs.devin.ai under the name Devin Desktop, and the old Windsurf docs URLs redirect there.1 The settings described here apply to the Cascade agent. The newer Devin Local agent in the same app replaces these levels with its own allow, ask and deny rules.1 If your settings panel looks different from this post, check which agent you’re using.
The four levels
You choose a level in the settings panel at the bottom right of the editor.1
| Level | What runs without asking | Who decides |
|---|---|---|
| Disabled | Nothing | You, every time |
| Allowlist Only | Commands matching your allow list | The list |
| Auto | Commands the model judges safe | The model (premium models only) |
| Turbo | Everything not on the deny list | Nobody, unless the deny list matches |
Source: the terminal docs.1
The first two are deterministic: the same command gets the same answer. Auto is a judgment call by a model, which is the same design Cursor uses for its Auto-review classifier and which Cursor itself says is not a security boundary.4 VS Code’s docs make the same point about their own terminal auto-approval: “a best-effort convenience, not a security boundary.”3 None of these vendors is wrong; a model reviewing commands catches a lot. It just isn’t something to rely on alone.
Turbo is the one to be careful with. It inverts the default: instead of listing what may run, you list what may not, and anything you forgot runs. Its safety is exactly as good as your deny list’s coverage of every destructive command, alias and script on your machine.
How allow and deny entries match
Entries are managed from the command card Cascade shows when it wants to run something.1
| Action on the card | What gets saved | What it matches |
|---|---|---|
| Allowlist → Allow | The exact command | Only that exact command |
| Allowlist → Prefix | The base command plus * |
Every command starting with the same tokens |
| Deny | The base command | Every command starting with the base command |
Source: the terminal docs.1
So git * on the allow list auto-runs git add -A, as the docs say, and also git reset --hard, git clean -fdx and git push --force.1 The Prefix button is convenient precisely because it is broad. The Allow button is narrow: it approves the command you’re looking at and nothing else.
Deny works on the base command. Denying rm covers rm index.py and rm -rf /.1 What it can’t see is a destructive action under a different name: a make clean target, an npm script, a Python one-liner that deletes a directory, or a database client running DROP TABLE. List matching reads the command’s text, not what the command does.
Practical rules:
- Prefer Allow over Prefix for anything that writes.
- Use Prefix only for read-only tools:
ls *,cat *,rg *. - Deny the obvious bases:
rm,mv,git,psql,mysql,mongosh,dropdb,docker,kubectl,terraform,aws,gcloud. Denyinggitcosts you a prompt forgit status; that’s the right trade in Turbo. - Review the lists monthly. Every Prefix click is a standing approval.
Team limits
Teams and Enterprise admins have two levers in the Admin Portal.1
A maximum level. If the admin sets the maximum to Auto, members can pick Disabled, Allowlist Only or Auto, but not Turbo.1 For most teams, capping at Allowlist Only or Auto is the single most useful setting.
Team-wide lists. Team allow and deny lists merge with each person’s lists. A command matching either the team or the user allow list auto-runs, unless a deny list matches; a deny match at either level means approval is required, and deny takes precedence.1
The merge has a sharp edge. Because allow lists add up, a member’s personal git * entry still auto-runs git push even if the team never allowed it, unless the team denies it. If there are commands no one should run unattended, put them on the team deny list rather than leaving them off the team allow list.
Hooks: the one hard block
Cascade Hooks run your script at fixed points: before and after reading code, writing code, running a command, using an MCP tool, and before a prompt.2 They load from three places and all of them run, in this order:
| Level | Location |
|---|---|
| System | /Library/Application Support/Devin/hooks.json (macOS), /etc/devin/hooks.json (Linux), with the old Windsurf paths as fallback |
| User | ~/.codeium/windsurf/hooks.json |
| Workspace | .devin/hooks.json (or the legacy .windsurf/hooks.json) |
Source: the Cascade Hooks docs.2
A pre_run_command hook receives JSON with tool_info.command_line and cwd.2
Code Data in JSON, the format software uses to pass records and settings.
{
"agent_action_name": "pre_run_command",
"tool_info": {
"command_line": "psql $DATABASE_URL -c 'DELETE FROM orders'",
"cwd": "/Users/you/project"
}
}
Exit code 2 blocks the command and shows your stderr to the agent; exit 0 lets it run.2 This works at every level, Turbo included, which makes it the only control in this post that says no rather than ask.
Three limits to plan for:
- Any other exit code lets the command run. A crash, a missing interpreter or a syntax error in your script fails open.2 Test the hook with a known-bad command after every change.
- Hooks don’t run in Restricted Mode. If a workspace is opened in Restricted Mode, hooks don’t load.2
- A workspace hook file is part of the repo. Anyone who can change
.devin/hooks.jsoncan change your policy. Put the rules that matter at the system level, which an MDM tool can manage.
A hook also reads the command text, like the lists. It is better than a list because it can parse the whole line, follow && and ;, and look inside -c strings, but it still can’t know what a script it calls will do.
A setup we would start from
- Level: Allowlist Only for daily work. Auto if you want fewer prompts and accept a model’s judgment. Turbo only in a throwaway environment.
- Allow list: exact commands for builds and tests; Prefix entries only for read-only tools.
- Deny list: destructive bases and every database and cloud CLI you have installed.
- Admins: cap the maximum level and keep a team deny list.
- Hook: a system-level
pre_run_commandhook that exits 2 for commands that must never run unattended, such asDROP,TRUNCATEandDELETEwithoutWHEREthrough any database client. - Credentials: keep production database URLs out of the shell environment Cascade’s terminal inherits. The dedicated terminal loads your
.zshrcor.bashrc, so anything exported there is in reach.1
What none of this covers
Levels, lists and hooks all act before a command runs. Once an allowed command reaches a database, none of them can say what it changed. If Cascade reports “updated the stale rows” after a psql call, the report is the agent’s account, not a record.
Two things help here. First, give the agent a database role that can’t do the damage you fear, so an allowed command is a limited command. Second, check the effect: compare what the agent said with what the database recorded. Our MCP config paths post shows where Windsurf keeps its MCP servers, which is where an agent’s database access usually comes from. To see an approval and a read-back on a real database in your browser, open the playground. To grade what agents on your machine can reach, including Windsurf’s MCP config, run npx deedglass scan (the grade, explained).
Questions people ask
Is Turbo mode safe?
It runs every command that isn’t on your deny list.1 It is as safe as the machine it runs on: fine in a disposable container with no credentials, risky on a laptop with production access.
Why did a denied command still run?
A deny entry makes Cascade ask; it doesn’t block.1 If you clicked approve, it ran. For a hard block, use a hook that exits 2.2
Does Auto mode work with every model?
No. The docs say Auto is only available for messages sent with premium models.1
Written with AI assistance and checked against our claims register.