Auto mode lets qcr execute all tool calls without prompting for approval. A 2-stage LLM safety classifier prevents destructive actions from being auto-approved.
# CLI flag
qcr --approval-mode never
# Environment variable
QCR_APPROVAL_MODE=never qcr
# In settings.json
{ "approval_mode": "never" }In auto mode, read-only tools (file reads, searches, listings) execute immediately. Write and execute tools pass through the safety classifier before running.
The classifier evaluates every non-read-only tool call in three stages:
Checks the tool name and arguments against always_allow and always_deny glob patterns. If a pattern matches, the decision is instant with no LLM call. always_deny takes priority over always_allow.
A short LLM call with a rules-based XML prompt. The classifier returns one of:
- ALLOW — safe to execute
- DENY — blocked with a reason
- ESCALATE — ambiguous, needs deeper analysis
Only runs when the fast check returns ESCALATE. Includes recent conversation context so the classifier can judge whether the tool call is proportional to the user's request. Returns ALLOW or DENY (no further escalation).
If either LLM call fails (network error, timeout, unparseable response), the classifier defaults to ALLOW. The rationale: the user explicitly chose auto mode, so the classifier is a safety net rather than a security boundary.
The fast check's built-in rules deny these patterns:
| Category | Examples |
|---|---|
| Destructive shell | rm -rf, git push --force, git reset --hard |
| Database | DROP TABLE, DELETE FROM, TRUNCATE |
| Privilege escalation | sudo, su, chmod 777 |
| System | kill -9, mkfs, dd, shutdown, reboot |
| Filesystem | DeletePath on system directories or outside CWD |
The fast check auto-allows:
| Category | Examples |
|---|---|
| Read-only | File reads, grep, glob, directory listings |
| Project writes | File writes/edits within the project directory |
| Safe git | add, commit, status, diff, log, branch |
| Build tools | install, build, test, lint |
Ambiguous operations (pipes, redirects, network calls, system config changes) are escalated to the deep check.
Add a safety_classifier section to settings.json:
{
"safety_classifier": {
"enabled": true,
"model": null,
"always_allow": [
"ReadFile", "Glob", "Grep", "Ls", "Now",
"ToolSearch", "AskUserQuestion", "Thinking",
"Memory", "TodoWrite"
],
"always_deny": [],
"custom_rules": []
}
}| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Turn the classifier on/off. When false, auto mode approves everything. |
model |
string or null | null |
Model override for classifier calls. When null, uses the session's active model. |
always_allow |
string[] | (see above) | Glob patterns that skip the classifier and are allowed. |
always_deny |
string[] | [] |
Glob patterns that skip the classifier and are denied. |
custom_rules |
string[] | [] |
Extra rule strings injected into the classifier prompt. |
Patterns match against tool names or tool-with-arguments strings:
{
"always_allow": ["Read*", "Glob", "Grep"],
"always_deny": [
"Shell(*rm -rf*)",
"Shell(*sudo*)",
"DeletePath"
],
"custom_rules": [
"Never allow access to /etc/passwd",
"Deny any curl command to internal network (192.168.*)"
]
}- Simple name:
"Shell"— exact match on tool name - Glob:
"Read*"— matches ReadFile, ReadDir, etc. - With args:
"Shell(*rm -rf*)"— matches tool name + argument content
always_deny is checked before always_allow. If both match the same tool call, the call is denied.
| Variable | Description |
|---|---|
QCR_SAFETY_CLASSIFIER |
Set to 0 or false to disable the classifier entirely |
QCR_SAFETY_CLASSIFIER_MODEL |
Override the model used for classifier LLM calls |
QCR_APPROVAL_MODE |
Set to never to enable auto mode |
QCR_APPROVAL_MODE=never \
qcr --print "Run the test suite and fix any failures"Use a fast, cheap model for safety checks while keeping a powerful model for the main conversation:
{
"approval_mode": "never",
"safety_classifier": {
"model": "gpt-4o-mini"
}
}{
"safety_classifier": {
"always_deny": [
"Shell(*rm*)",
"Shell(*git push*)",
"DeletePath",
"Shell(*docker rm*)"
]
}
}{
"safety_classifier": {
"always_allow": [
"Shell(*cargo test*)",
"Shell(*npm run*)",
"WriteFile",
"EditFile"
]
}
}