Cursor’s built-in allowlist works at executable level, as far as I could tell. Shell(python) means trusting every Python script. Shell(git) means allowing git push --force alongside git status. Happy to be wrong on this.
I wanted to auto-accept git status but not git push. Allow one specific Python script but not every Python invocation. And have a deny list that catches dangerous patterns regardless of what’s allowed.
So I built command rules. A JSON config with allow and deny patterns that match the full command text:
{
"allow": [
{ "group": "Shell (safe)", "patterns": ["ls *", "cd *", "git status*", "git diff*"] }
],
"deny": [
{ "group": "Destructive", "patterns": ["rm ", "--force", "--hard"] }
]
}
Deny always wins. If a command matches an allow pattern but contains a deny keyword anywhere in the text, it won’t auto-run and you decide as usual. This also catches chained commands: ls && rm -rf / won’t auto-run because rm appears in the full string.
The config is hot-reloaded. Edit the JSON while Cursor is running and changes take effect on the next confirmation.
This is part of PocketCursor, which started as a way to control Cursor from your phone via Telegram. It uses CDP to interact with Cursor’s UI, which also makes automation like this possible. Every auto-accepted command sends a notification, so you always know what ran.
About 100 lines of Python. MIT license.
Curious if others have been wanting finer control over this.